для выполнения произвольного кода при остановке на точке останова ... Могу ли я обмануть Питона, заставив его думать, что код выполняется в реальной локальной области этого фрейма?
Это позволяет отладчик Python, pdb. Например, предположим, что вы отлаживаете файл tests/scopeTest.py
, и в вашей программе есть следующая строка, где переменная не была объявлена в самой программе:
print (NOT_DEFINED_IN_PROGRAM)
, поэтому выполнение кода python tests/scopeTest.py
приведет к:
NameError: name 'NOT_DEFINED_IN_PROGRAM' is not defined
Теперь вы хотели бы определить эту переменную, когда она остановлена на этой строке в отладчике, и продолжить выполнение программы, используя эту переменную, как если бы она была определена в программе все время. Другими словами, вы хотели бы осуществить изменение в этой области, чтобы вы могли продолжить выполнение с этим постоянным изменением. Это действительно возможно:
$ python -m pdb tests/scopeTest.py
> /home/user/tests/scopeTest.py(1)<module>()
-> print (NOT_DEFINED_IN_PROGRAM)
(Pdb) 'NOT_DEFINED_IN_PROGRAM' in locals()
False
(Pdb) NOT_DEFINED_IN_PROGRAM = 5
(Pdb) 'NOT_DEFINED_IN_PROGRAM' in locals()
True
(Pdb) step
5
Pdb делает это через compile
и exec
в своей функции default
, которая эквивалентна:
code = compile(line + '\n', <stdin>, 'single')
exec(code, self.curframe.f_globals, self.curframe_locals)
, где self.curframe
- определенный кадр. Теперь self.curframe_locals
не является self.curframe.f_locals
, потому что, как говорит функция setup
:
# The f_locals dictionary is updated from the actual frame
# locals whenever the .f_locals accessor is called, so we
# cache it here to ensure that modifications are not overwritten.
self.curframe_locals = self.curframe.f_locals
Надеюсь, это поможет, и это то, что вы имели в виду!
Обратите внимание, что даже в этом случае, если вы захотите, например, заменить функцию в контексте отлаживаемой программы на версию с исправленными обезьянами, например:
newGlobals['abs'] = myCustomAbsFunction
exec(code, newGlobals, locals)
область действия myCustomAbsFunction
не будет пользовательской программой, но будет контекстом, где была определена эта функция, то есть отладчиком! Есть и способ обойти это, но, как об этом специально не спрашивают, на данный момент это оставлено как упражнение для читателя. ^ __ ^