Python类方法中exec定义的函数如何访问实例self?
类方法中动态定义依赖实例的函数并在PDB中调用的解决方案
问题描述
以下代码在进入PDB会话后调用func()会触发NameError,提示'self'未定义,但func已被识别:
class A: def __init__(self): self.name = "foo" def hello(self): exec("def func():\n print(self.name)") import pdb; pdb.set_trace() aa = A() aa.hello()
类似的,尝试在动态函数中调用实例方法时也会遇到相同问题:
class A: def foo(self): print("running foo") def hello(self): exec("def func():\n self.foo()") import pdb; pdb.set_trace() aa = A() aa.hello()
核心问题是:动态定义的func无法访问当前类实例的self,因为exec执行的代码块默认不捕获外部作用域的self。
解决方法
方法1:通过默认参数绑定self引用
修改exec中的函数定义,将当前self作为默认参数传入,让func在定义时就绑定实例引用:
class A: def __init__(self): self.name = "foo" def hello(self): # 将self绑定为func的默认参数self_ref exec("def func(self_ref=self):\n print(self_ref.name)") import pdb; pdb.set_trace() aa = A() aa.hello()
进入PDB后直接调用func()即可,默认参数会自动传入绑定的实例,正常输出foo。
对于调用实例方法的场景,同样修改:
class A: def foo(self): print("running foo") def hello(self): exec("def func(self_ref=self):\n self_ref.foo()") import pdb; pdb.set_trace() aa = A() aa.hello()
方法2:通过exec的globals参数注入self
利用exec的第二个参数(全局命名空间),将self注入到动态代码的执行环境中,让func能直接访问:
class A: def __init__(self): self.name = "foo" def hello(self): # 把self传入exec的globals字典 exec("def func():\n print(self.name)", {"self": self}) import pdb; pdb.set_trace() aa = A() aa.hello()
此方法下,exec执行时的全局命名空间包含self,func定义时可以直接使用该变量,PDB中调用func()即可正常运行。
方法3:将self赋值给局部变量供动态函数访问
在exec前将self赋值给一个局部变量,然后在动态函数中使用该变量:
class A: def foo(self): print("running foo") def hello(self): # 把self赋值给局部变量instance instance = self # 在动态函数中使用instance代替self exec("def func():\n instance.foo()") import pdb; pdb.set_trace() aa = A() aa.hello()
这种方式利用了Python闭包对外部局部变量的捕获特性,func可以访问到instance(即当前实例)。
内容的提问来源于stack exchange,提问作者zkytony
相关产品推荐
相关产品推荐

