代码之家  ›  专栏  ›  技术社区  ›  phant0m Grijesh Chauhan

装饰方法

  •  4
  • phant0m Grijesh Chauhan  · 技术社区  · 16 年前

    在我的python应用程序中,我使用事件在不同的插件之间进行通信。 现在,我不想手动将这些方法注册到事件中,而是想使用装饰器来为我实现这一点。

    我想让它看起来像这样:

    @events.listento('event.name')
    def myClassMethod(self, event):
        ...
    

    我第一次尝试这样做:

    def listento(to):
        def listen_(func):
            myEventManager.listen(to, func)
            def wrapper(*args, **kwargs):
                return func(*args, **kwargs)
            return func
        return listen_
    

    当我呼唤 myEventManger.listen('event', self.method) 从实例内部来看,一切都运行良好。但是,如果我使用decorator方法, self 从未传递参数。

    在互联网上搜索解决方案后,我尝试的另一种方法是使用类作为装饰:

    class listen(object):
        def __init__(self, method):
            myEventManager.listen('frontend.route.register', self)
            self._method = method
            self._name = method.__name__
            self._self = None
    
        def __get__(self, instance, owner):
            self._self = instance
            return self
    
        def __call__(self, *args, **kwargs):
            return self._method(self._self, *args, **kwargs)
    

    这种方法的问题在于我不太了解 __get__ 我不知道如何合并这些参数。 只是为了测试,我尝试使用一个固定的事件来监听,但是使用这种方法,什么都不会发生。当我添加打印语句时,我可以看到 __init__ 被称为。 如果我添加了一个附加的“旧样式”事件注册,两者都是 第二代 __call__ 尽管有了新的装饰器,执行该事件,该事件仍然有效。

    什么是实现我所寻找的最好的方法,或者我只是错过了一些装饰师的重要概念?

    2 回复  |  直到 11 年前
        1
  •  4
  •   Peter Milley    16 年前

    decorator方法不起作用,因为在构造类时调用decorator,而不是在构造实例时调用decorator。当你说

    class Foo(object):
      @some_decorator
      def bar(self, *args, **kwargs):
        # etc etc
    

    然后 some_decorator 将在构造类foo时调用,并且它将通过 未绑定的 方法,而不是实例的绑定方法。这就是为什么 self 不会通过的。

    另一方面,第二种方法只要你创造了 每个类的对象, 如果你有点聪明。如果你定义 listen 如上所述,然后定义

    class Foo(object):
      def __init__(self, *args, **kwargs):
        self.some_method = self.some_method # SEE BELOW FOR EXPLANATION
        # etc etc
      @listen
      def some_method(self, *args, **kwargs):
        # etc etc
    

    然后 listen.__get__ 当有人打电话的时候 f.some_method 直接为一些 f …但你计划的重点是没有人这样做!事件回调机制正在调用 直接实例,因为这就是它被传递的原因 实例正在调用它在创建时存储的未绑定方法。 听我说。 永远不会接到电话 _self 无法正确设置参数… 除非 你明确地访问 self.some_method 你自己,就像我在 __init__ 以上方法。然后 听我说。 将在创建实例时调用,并且 自我 将正确设置。

    问题是(a)这是一次可怕的黑客攻击,(b)如果你试图创建两个 Foo 然后第二个将覆盖 自我 由第一个设置,因为仍然只有一个 正在创建的对象,它与类关联,而不是实例。如果你只使用一个 实例,那么你很好,但是如果你必须让事件触发两个不同的 那么你只需要使用你的“老式”活动注册。

    TL,DR版本:修饰方法修饰 未绑定的 方法,而您希望事件管理器通过 跳跃 实例的方法。

        2
  •  3
  •   Alex Martelli    16 年前

    您的部分代码是:

        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return func
    

    它定义 wrapper 然后完全忽略它并返回 func 相反。很难说这在你的代码中是否是一个真正的问题,因为很明显你没有发布它(例如 myEventManagre , myEvnetManager ,&c),但如果这就是您在实际代码中所做的, 显然是你问题的一部分。

    推荐文章