Я не эксперт pdb
, поэтому, пожалуйста, поправьте меня, если я ошибаюсь.
Вот вам MCVE :
import pdb
def f():
def g(n): return 2*n
pdb.set_trace()
f()
Теперь, в pdb
, как и ожидалось:
ipdb> g(5)
10
Но откуда взято g
имя?
ipdb> 'g' in globals()
False
ipdb> 'g' in locals()
True
Хорошо, g
в locals()
переменных f
. Когда вы создаете список или диктовку, у вас есть новые locals()
переменные:
ipdb> [locals() for _ in range(1)]
[{'_': 0, '.0': <range_iterator object at 0x7f1924003d80>}]
Следовательно, в понимании списка / слова g
не входит ни в locals()
, ни в globals()
:
ipdb> [g(1) for _ in range(1)]
*** NameError: name 'g' is not defined
Теперь большой вопрос: почему это работает в запущенной программе, а не в ipdb
? Я надеюсь, у меня есть начало объяснения:
import pdb
import inspect
def f():
def g(n): return 2*n
print([g(1) for _ in range(1)])
print([inspect.stack()[1].frame.f_locals for _ in range(1)])
pdb.set_trace()
f()
# output:
[2] # it works because...
[{'g': <function f.<locals>.g at 0x7f1916692488>}] # ...g is in the parent stack frame
В ipdb
, как замечено:
ipdb> [g(1) for _ in range(1)]
*** NameError: name 'g' is not defined
Но если вы берете g
вручную из родительского фрейма, это работает:
ipdb> [inspect.stack()[1].frame.f_locals for _ in range(1)]
[{'g': <function f.<locals>.g at 0x7f1916692488>, '__return__': None}]
ipdb> [inspect.stack()[1].frame.f_locals['g'](1) for _ in range(1)]
[2]
Вывод: похоже, что ipdb
не дает прямого доступа к значениям, хранящимся в родительском фрейме, в отличие от работающей программы.
Обратите внимание, что это, вероятно, в значительной степени зависит от реализации Python. (Я использовал CPython.)