jor*_*gen 4 python decorator python-2.7 python-decorators
下面非常简化的代码中的观察者模式运行良好.我想有一个装饰器@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")
Run Code Online (Sandbox Code Playgroud)
直到你有一个实例的方法来约束你不能注册绑定方法来.单独的函数装饰器没有用于检测何时创建实例的上下文.
您可以使用元类/装饰器组合方法:
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
Run Code Online (Sandbox Code Playgroud)
这将注册所有直接定义的方法cls,并标记为观察者; 标记是用装饰器完成的:
def on_event_method(f):
f.__observer__ = True
return f
Run Code Online (Sandbox Code Playgroud)
然后将其用作:
class O2(object):
__metaclass__ = ObservingMeta
def __init__(self, name):
self.name = name
@on_event_method
def eventx(self, data):
print self.name + " Event: " + data
Run Code Online (Sandbox Code Playgroud)
请注意,将方法存储在Observable单例中会使实例保持活动状态; 如果您创建O2绑定eventx方法的实例,则引用该实例,并通过保留对方法的引用,这意味着如果删除了对它们的所有其他引用,则实例永远不会被垃圾回收.
请参阅使用python WeakSet启用回调功能,以便如何使用弱引用代替仅在删除基础实例之前保留方法,而不会无限期地保持实例的活动.