Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Closure lost during callback defined in exec()

It's my third day using Python, so forgive newbie mistakes. So here's my working code. person.test() registers a callback with the boss, the boss calls the callback, everything works fine.

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()

However, if I change move the callback into an exec(), the closure is lost. The callback runs, but self and data are unknown so the call to self.woot(data) fails.

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()

I tried to compile() too, no luck. Any thoughts? I really don't want to manually carry a copy of self/data through the boss and back, because my real-life code is much more convoluted. I really need a way to maintain the closure.

like image 997
JeramieH Avatar asked Sep 03 '25 08:09

JeramieH


1 Answers

If you only pass locals (as the global data for the function), then things more or less work:

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())

of course, if you need the globals as well, you can pack them together:

def test(self, boss, data):
  namespace = globals().copy()
  local_copy = locals().copy()
  namespace.update(local_copy)
  x = 'def foo(): pass'
  exec(x, namespace)
like image 106
mgilson Avatar answered Sep 04 '25 22:09

mgilson