如何在Python 2.7的观察者模式中使用装饰器 [英] How to use decorator in observer pattern for Python 2.7

查看:79
本文介绍了如何在Python 2.7的观察者模式中使用装饰器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面非常简化的代码中的观察者模式效果很好。我想有一个装饰器 @on_event 在Observable单例中进行注册。

The observer pattern in the very simplified code below works well. I would like to have have a decorator @on_event that does the registration in the Observable singleton.

在O2类中下面这是行不通的。问题当然是在实例创建之前调用了装饰器on_event,并且注册将绑定到未绑定方法 event 。在某种程度上,我必须延迟注册,直到O2对象被初始化为止。也许无需多说,但是我要添加的O2就是下面的代码中的装饰器。

In class O2 below this does not work. The problem is of course that the decorator on_event get's called prior to the instance is created, and the registration will be to the unbound method event. In some way I have to delay the registration until the O2 object is initialized. Maybe needless to say but all I want to add in O2 is the decorator as in the code below.

但是可以肯定的是必须有解决方案吗?我在Google周围搜索,但找不到任何东西,并尝试了几种方法。

But for sure there must be a solution to this? I have googled around but cannot find anything, and have tried several approaches.

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


推荐答案

您无法注册绑定方法直到您有将方法绑定到的实例为止。单独的函数装饰器没有上下文来检测实例的创建时间。

You cannot register bound methods until you have an instance for the method to be bound to. A function decorator alone does not have the context to detect when an instance has been created.

您可以改用元类/装饰器组合方法:

You could use a metaclass / decorator combined approach instead:

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 上定义的所有标记为观察者的方法 ;标记是由装饰器完成的:

This registers all methods directly defined on cls that are marked as observers; the marking is done with a decorator:

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 方法将引用该实例,并保留对方法的引用,即如果删除对实例的所有其他引用,则永远不会进行垃圾回收。

Do note that storing the methods in your Observable singleton keeps the instances alive; if you create instances of O2 the bound eventx methods reference the instance, and by keeping references to the methods that means the instances are never garbage collected if all other references to them are deleted.

请参见使用python WeakSet启用回调功能,了解如何使用弱引用,而不是仅保留方法的选项卡,直到删除基础实例为止,而无需保持实例无限期地存活。

See using python WeakSet to enable a callback functionality for how you could use weak references instead to only keep tabs on methods until the underlying instance has been deleted, without keeping the instances alive indefinitely.

这篇关于如何在Python 2.7的观察者模式中使用装饰器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆