Python:猴子补丁修复缺失导入失效问题排查
猴子补丁修复缺失导入后原方法仍无法获取导入的问题
问题背景
MyClass是gdb.Command的子类,尝试通过猴子补丁给mymodule.MyClass.invoke方法补加getopt导入,但原方法old_invoke()执行时依然抛出NameError,提示找不到getopt。
操作步骤及报错
(gdb) pi >>> import mymodule >>> old_invoke = mymodule.MyClass.invoke >>> def new_invoke(self, *k, **kw): ... print("New invoke") ... import getopt ... old_invoke(self, *k, **kw) ... >>> mymodule.MyClass.invoke = new_invoke >>> (gdb) my_gdb_command New invoke Python Exception <class 'NameError'> name 'getopt' is not defined: Error occurred in Python: name 'getopt' is not defined
相关文件及加载方式
mymodule.py
import gdb class MyClass(gdb.Command): ... def invoke(self, arg, from_tty): options, remainder = getopt.getopt(args, 'p:s:t:o:') ... MyClass()
myothermodule.py
import mymodule ...
加载命令
(gdb) source myothermodule.py
问题原因
Python函数的作用域是定义时确定的,原invoke方法在mymodule模块中定义,该模块未导入getopt。即使在猴子补丁的new_invoke中导入getopt,也只是在new_invoke的局部作用域或当前交互环境中生效,无法进入原invoke方法所在的模块命名空间,因此原方法找不到getopt。
解决方法
方法1:将getopt导入到mymodule的命名空间
直接把getopt添加到mymodule模块的全局命名空间中,让原invoke方法能在自己的模块环境中找到它:
(gdb) pi >>> import mymodule >>> import getopt >>> mymodule.getopt = getopt >>> old_invoke = mymodule.MyClass.invoke >>> def new_invoke(self, *k, **kw): ... print("New invoke") ... old_invoke(self, *k, **kw) ... >>> mymodule.MyClass.invoke = new_invoke
方法2:修改原invoke方法的全局字典
直接修改原invoke方法的__globals__属性,把getopt注入到它定义时的全局环境:
(gdb) pi >>> import mymodule >>> import getopt >>> old_invoke = mymodule.MyClass.invoke >>> old_invoke.__globals__['getopt'] = getopt >>> def new_invoke(self, *k, **kw): ... print("New invoke") ... old_invoke(self, *k, **kw) ... >>> mymodule.MyClass.invoke = new_invoke
内容的提问来源于stack exchange,提问作者user1266174
相关产品推荐
相关产品推荐

