Python中字典回调的引用
我有一个类,这个类里定义了一些回调函数(这里叫做 cb1
和 cb2
)。我还保存了一个这些函数的映射表,想在某个事件发生后调用它们。
class Foo:
cb1 = None
cb2 = None
def test(self, input):
for (name, callback) in map:
if name == input:
if callback: callback()
...
map = {'one':cb1, 'two':cb2}
def mycallback():
print "mycallback()"
f = Foo()
f.cb1 = mycallback # Register our callback
f.test('one') # Nothing happens
你能发现问题吗?
问题是,当这个类被初始化的时候,cb1 和 cb2 的值(这两个值都是 None
)会被复制到映射表里。所以即使用户“注册”了回调函数(通过给 cb1
赋值),映射表里的值依然是 None
,这样就不会调用任何函数。
因为在Python中没有“引用传递”这种说法,我该怎么解决这个问题呢?
5 个回答
1
添加一个注册功能。在 Foo 类中:
def register(self, name, cb): self.map[name] = cb
而不是:
f.cb1 = mycallback
使用:
f.register('one', mycallback)
1
为什么你需要为自定义回调设置一个不同的变量,而不是直接用执行它的那个变量呢?如果你用同一个变量,这个问题就解决了。
用一些简单的语法糖,它可以看起来像这样:
class CallbackMap(object):
pass
class Foo(object):
callbacks = CallbackMap()
def test(self, input):
callback = getattr(Foo.callbacks, input)
if callback: callback()
# setup defaults
Foo.callbacks.one = None
Foo.callbacks.two = some_default_callback
# customize
def mycallback():
print "mycallback()"
f = Foo()
Foo.callbacks.one = mycallback # Register our callback
f.test('one') # works
12
为什么不让你的类明确地处理注册呢?
import collections
class Foo(object):
handlers = None
def __init__(self):
self.handlers = collections.defaultdict(set)
def register(self, event, callback):
self.handlers[event].add(callback)
def fire(self, event, **kwargs):
for handler in self.handlers.get(event, []):
handler(**kwargs)
foo = Foo()
foo.register('one', mycallback)
foo.fire('one')