下面非常简化的代码中的观察者模式效果很好。我希望有一个装饰器@on_event
在Observable单例中进行注册。
在下面的O2类中,这不起作用。问题当然是装饰器on_event在创建实例之前被调用,注册将是未绑定方法event
。在某种程度上,我必须延迟注册,直到初始化O2对象。也许不用说了,但我想在O2中添加的是装饰器,如下面的代码所示。
但是肯定必须有解决方案吗?我用Google搜索但找不到任何东西,并尝试了几种方法。
class Observable(object):
_instance = None
@classmethod
def instance(cls):
if not cls._instance:
cls._instance = Observable()
return cls._instance
def __init__(self):
self.obs = []
def event(self, data):
for fn in self.obs:
fn(data)
def on_event(f):
def wrapper(*args):
return f(*args)
Observable.instance().obs.append(f)
return wrapper
class O(object):
def __init__(self, name):
self.name = name
Observable.instance().obs.append(self.event)
def event(self, data):
print self.name + " Event: " + data
class O2(object):
def __init__(self, name):
self.name = name
@on_event
def eventx(self, data):
print self.name + " Event: " + data
if __name__ == "__main__":
o1 = O("o1")
Observable.instance().event("E1")
o2 = O2("o2")
Observable.instance().event("E2")
答案 0 :(得分:5)
在将绑定到的方法实例之前,无法注册绑定方法。单独的函数装饰器没有用于检测何时创建实例的上下文。
您可以使用元类/装饰器组合方法:
class ObservingMeta(type):
def __call__(cls, *args, **kw):
instance = super(ObservingMeta, cls).__call__(*args, **kw)
for attr in vars(cls).values():
if hasattr(attr, '__observer__'):
# register bound method
bound = attr.__get__(instance, cls)
Observable.instance().obs.append(bound)
return instance
这将注册在cls
上定义的所有直接方法,这些方法被标记为观察者;标记是由装饰者完成的:
def on_event_method(f):
f.__observer__ = True
return f
然后用作:
class O2(object):
__metaclass__ = ObservingMeta
def __init__(self, name):
self.name = name
@on_event_method
def eventx(self, data):
print self.name + " Event: " + data
请注意,将方法存储在Observable
单例中会使实例保持活动状态;如果您创建O2
的实例,则绑定的eventx
方法引用该实例,并通过保留对方法的引用来表示如果删除了对它们的所有其他引用,则实例永远不会被垃圾回收。
请参阅using python WeakSet to enable a callback functionality,了解如何使用弱引用代替只保留方法,直到基础实例被删除,而不会无限期地保持实例生效。