3

这是我使用 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(),则关闭将丢失。回调运行,但selfdata是未知的,因此对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() ,但没有运气。有什么想法吗?我真的不想通过老板手动携带自我/数据的副本并返回,因为我的真实代码更加复杂。我真的需要一种方法来保持关闭。

4

2 回答 2

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)
于 2015-03-09T20:26:21.577 回答
2

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

self是一个自由变量callback,如果您阅读locals()的文档,您会发现:

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

现在从exec()的文档中:

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

因此,当我们将两个不同的对象传递给exec()字典时,它locals()实际上是空的,callback()因为它无法再访问自由变量,因此@mgilson 建议的解决方案传递了合并版本locals()并且globals()应该为你做。

于 2015-03-09T20:37:07.240 回答