在exec()中定义的回调期间关闭丢失

时间:2015-03-09 20:00:19

标签: python python-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()

我也尝试编译(),没有运气。有什么想法吗?我真的不想通过老板和后面手动携带自我/数据的副本,因为我的现实代码更复杂。我真的需要一种方法来保持关闭。

2 个答案:

答案 0 :(得分:3)

如果你只传递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)

答案 1 :(得分:2)

为什么您当前的代码会失败?

selfcallback的免费变量,如果您阅读locals()的文档,您会发现:

  

在函数中调用时,locals()返回自由变量   阻止,但不在类阻止

现在来自exec()的文档:

  

如果exec获得两个单独的对象作为全局和本地,代码将   执行就像它嵌入在类定义中一样。

因此,当我们将两个不同的对象传递给exec()时,locals()字典对于callback()实际上是空的,因为它不能再访问自由变量,因此solution suggested by @mgilson通过合并版locals()globals()应该为您完成。