在 exec() 中定义的回调期间关闭丢失
Closure lost during callback defined in exec()
这是我使用 Python 的第三天,所以请原谅新手的错误。所以这是我的工作代码。 person.test()向老板注册回调,老板调用回调,一切正常。
class Boss:
def registerCallback(self,cb):
self.cb = cb
def doCallback(self):
self.cb()
class Person:
def woot(self,data):
print("Woot! ",data)
def test(self,boss,data):
def callback ():
self.woot(data)
boss.registerCallback(callback)
boss = Boss()
person = Person()
person.test(boss,1)
boss.doCallback()
但是,如果我将回调移动到 exec() 中,闭包就会丢失。回调运行,但 self 和 data 未知,因此调用 self.woot(data)失败。
class Boss:
def registerCallback(self,cb):
self.cb = cb
def doCallback(self):
self.cb()
class Person:
def woot(self,data):
print("Woot! ",data)
def test(self,boss,data):
x = "def callback():\n self.woot(data)\nboss.registerCallback(callback)"
exec(x,globals(),locals())
boss = Boss()
person = Person()
person.test(boss,1)
boss.doCallback()
我也试过 compile() ,没有成功。有什么想法吗?我真的不想手动携带 self/data 的副本通过老板并返回,因为我的真实代码要复杂得多。我真的需要一种方法来保持闭包。
如果你只传递 locals
(作为函数的全局数据),那么事情或多或少会起作用:
class Person:
def woot(self,data):
print("Woot! ",data)
def test(self,boss,data):
x = "def callback():\n self.woot(data)\nboss.registerCallback(callback)"
exec(x, locals())
当然,如果你也需要全局变量,你可以将它们打包在一起:
def test(self, boss, data):
namespace = globals().copy()
local_copy = locals().copy()
namespace.update(local_copy)
x = 'def foo(): pass'
exec(x, namespace)
为什么您当前的代码失败了?
self
是 callback
的自由变量,如果您阅读 locals()
的文档,您会发现:
Free variables are returned by locals()
when it is called in function
blocks, but not in class blocks.
现在来自 exec()
的文档:
If exec
gets two separate objects as globals and locals, the code will
be executed as if it were embedded in a class definition.
因此,当我们将两个不同的对象传递给 exec()
时,locals()
字典对于 callback()
实际上是空的,因为它无法再访问自由变量,因此 通过 locals()
和 globals()
的合并版本应该为你做。
这是我使用 Python 的第三天,所以请原谅新手的错误。所以这是我的工作代码。 person.test()向老板注册回调,老板调用回调,一切正常。
class Boss:
def registerCallback(self,cb):
self.cb = cb
def doCallback(self):
self.cb()
class Person:
def woot(self,data):
print("Woot! ",data)
def test(self,boss,data):
def callback ():
self.woot(data)
boss.registerCallback(callback)
boss = Boss()
person = Person()
person.test(boss,1)
boss.doCallback()
但是,如果我将回调移动到 exec() 中,闭包就会丢失。回调运行,但 self 和 data 未知,因此调用 self.woot(data)失败。
class Boss:
def registerCallback(self,cb):
self.cb = cb
def doCallback(self):
self.cb()
class Person:
def woot(self,data):
print("Woot! ",data)
def test(self,boss,data):
x = "def callback():\n self.woot(data)\nboss.registerCallback(callback)"
exec(x,globals(),locals())
boss = Boss()
person = Person()
person.test(boss,1)
boss.doCallback()
我也试过 compile() ,没有成功。有什么想法吗?我真的不想手动携带 self/data 的副本通过老板并返回,因为我的真实代码要复杂得多。我真的需要一种方法来保持闭包。
如果你只传递 locals
(作为函数的全局数据),那么事情或多或少会起作用:
class Person:
def woot(self,data):
print("Woot! ",data)
def test(self,boss,data):
x = "def callback():\n self.woot(data)\nboss.registerCallback(callback)"
exec(x, locals())
当然,如果你也需要全局变量,你可以将它们打包在一起:
def test(self, boss, data):
namespace = globals().copy()
local_copy = locals().copy()
namespace.update(local_copy)
x = 'def foo(): pass'
exec(x, namespace)
为什么您当前的代码失败了?
self
是 callback
的自由变量,如果您阅读 locals()
的文档,您会发现:
Free variables are returned by
locals()
when it is called in function blocks, but not in class blocks.
现在来自 exec()
的文档:
If
exec
gets two separate objects as globals and locals, the code will be executed as if it were embedded in a class definition.
因此,当我们将两个不同的对象传递给 exec()
时,locals()
字典对于 callback()
实际上是空的,因为它无法再访问自由变量,因此 locals()
和 globals()
的合并版本应该为你做。