在框架的原始本地范围内执行代码
我编写了一个远程 Python 调试器,我需要的功能之一是在断点处停止时执行任意代码。我的调试器使用以下命令来执行从远程调试器接收到的代码:
exec (compile(code, '<string>', 'single') , frame.f_globals, frame.f_locals)
这在大多数情况下工作正常,但我注意到了一些问题。
赋值语句实际上并未应用于原始本地字典。这可能是因为 f_locals 应该是只读的。
如果在类方法中停止,则无法访问受保护的属性(以双下划线开头的名称)。我假设这是由于 Python 对受保护属性执行的名称修改所致。
所以我的问题是,有没有办法绕过这些限制?我可以欺骗 Python 让它认为代码是在该帧的实际本地范围内执行的吗?
我正在使用 CPython 2.7,并且我愿意接受特定于该版本的解决方案/黑客。
I've written a remote Python debugger and one of the features I need is to execute arbitrary code while stopped at a breakpoint. My debugger uses the following to execute code received from the remote debugger:
exec (compile(code, '<string>', 'single') , frame.f_globals, frame.f_locals)
This works fine for the most part, but I've noticed a couple issues.
Assignment statements aren't actually applied to the original locals dictionary. This is probably due to the fact that f_locals is supposed to be read-only.
If stopped within a class method, accessing protected attributes (names beginning with double underscore) does not work. I'm assuming this is due to the name mangling that Python performs on protected attributes.
So my question is, is there a way around these limitations? Can I trick Python into thinking that the code is being executed in the actual local scope of that frame?
I'm using CPython 2.7, and I'm willing to accept a solution/hack specific to this version.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不完全是这样,但是函数的字节码不会查看局部变量,而是使用一种简单但关键的优化,即局部变量位于简单的数组中,从而避免了运行时查找。避免这种情况的唯一方法(并使函数大大、大大变慢)是编译不同的代码,例如以
exec ''
开头的代码强制编译器避免优化(在 Python 2 中;在 Python 3 中不行)。如果您需要使用现有的字节码,那么您就不走运了:没有方法可以完成您想要的任务。是的,所以这个问题确实允许一种解决方法:在名称前面添加
_Classname
来模仿编译器的行为。请注意,双下划线前缀意味着 private:protected 将是单下划线(并且不会给您带来任何麻烦)。私有名称专门用于避免名称绑定在子类中的意外类(并且可以很好地用于该目的,尽管并不完美,并且不能用于其他任何目的;-)。Not exactly, but the bytecode for the function will not look at
locals
, using rather a simple but crucial optimization whereby local variables are in a simple array, avoiding runtime lookups. The only way to avoid this (and make the function much, much slower) is compiling different code, e.g. code starting with anexec ''
to force the compiler to avoid the optimization (in Python 2; no way, in Python 3). If you need to work with existing bytecode, you're out of luck: there is no way to accomplish what you desire.Yep, so this issue does allow a workaround: prepend
_Classname
to the name to mimic what the compiler does. Note that double-underscore prefixes means private: protected would be a single underscore (and would give you no trouble). Private names are specifically meant to avoid accidental classes with names bound in subclasses (and work decently for that one purpose, though not perfectly, and not for anything else;-).我不确定我是否正确理解了您的意思,但是
exec
确实使用代码内的赋值填充了locals
参数:也许
f_locals
没有不允许写入。I'm not sure I've understood you correctly, but
exec
does populate thelocals
parameter with assignments inside the code:Perhaps
f_locals
doesn't allow writes.Python 调试器 pdb 允许这样做。例如,假设您正在调试文件
tests/scopeTest.py
,并且您的程序中有以下行,其中变量尚未在程序本身中声明:因此运行代码
python tests/scopeTest.py
会导致:现在,您希望在调试器中停在该行时定义该变量,并让程序继续执行,使用该变量就好像它已经被执行一样一直在程序中定义。换句话说,您希望在该范围内实现更改,以便您可以继续执行该更改永久。实际上是可能的:
Pdb 通过其
default
函数中的compile
和exec
来完成此操作,这相当于:where
self .curframe
是一个特定的框架。现在,self.curframe_locals
不是self.curframe.f_locals
,因为,正如setup
函数所述:希望有帮助,这就是你的意思!
请注意,即使如此,您是否希望将正在调试的程序上下文中的函数替换为经过猴子修补的版本,例如:
myCustomAbsFunction
的范围不是将是用户程序,但将是定义该函数的上下文,即调试器!也有一种解决方法,但由于没有具体询问,因此目前将其作为练习留给读者。 ^__^The Python debugger, pdb, allows this. For example, let's say you are debugging the file
tests/scopeTest.py
, and you have the following line in your program, where the variable hasn't been declared in the program itself :so that running the code
python tests/scopeTest.py
would result in :Now you would like to define that variable when stopped at that line in the debugger, and have the program continue executing, using that variable as if it had been defined in the program all along. In other words, you would like to effect the change within that scope, so that you can continue execution with that change permanent. It is actually possible :
Pdb does this through a
compile
andexec
in itsdefault
function, which does the equivalent of :where
self.curframe
is a specific frame. Now,self.curframe_locals
is notself.curframe.f_locals
, because, as thesetup
function says :Hope that helps, and is what you meant!
Take note that, even then, should you want to, for example, replace a function in the context of the program being debugged with a monkey-patched version, such as:
the scope of the
myCustomAbsFunction
is not going to be the user program, but is going to be the context of where that function was defined, which is the debugger! There is a way around that too, but as it wasn't specifically asked, it is left as an exercise for the reader, for now. ^__^