Decorating a method

旧巷老猫 提交于 2019-12-05 16:55:24

The decorator approach isn't working because the decorator is being called when the class is constructed, not when the instance is constructed. When you say

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

then some_decorator will be called when the class Foo is constructed, and it will be passed an unbound method, not the bound method of an instance. That's why self isn't getting passed.

The second method, on the other hand, could work as long as you only ever create one object of each class you use the decorator on, and if you're a bit clever. If you define listen as above and then define

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

Then listen.__get__ would be called when someone tried to call f.some_method directly for some f...but the whole point of your scheme is that no-one's doing that! The event call back mechanism is calling the listen instance directly 'cause that's what it gets passed and the listen instance is calling the unbound method it squirrelled away when it was created. listen.__get__ won't ever get called and the _self parameter is never getting set properly...unless you explicitly access self.some_method yourself, as I did in the __init__ method above. Then listen.__get__ will be called upon instance creation and _self will be set properly.

Problem is (a) this is a horrible, horrible hack and (b) if you try to create two instances of Foo then the second one will overwrite the _self set by the first, because there's still only one listen object being created, and that's associated to the class, not the instance. If you only ever use one Foo instance then you're fine, but if you have to have the event trigger two different Foo's then you'll just have to use your "old style" event registration.

The TL,DR version: decorating a method decorates the unbound method of the class, whereas you want your event manager to get passed the bound method of an instance.

Part of your code is:

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

which defines wrapper then completely ignores it and returns func instead. Hard to say whether this is a real problem in your real code because obviously you're not posting that (as proven by typoes such as myEventManagre, myEvnetManager, &c), but if that's what you're doing in your actual code it is obviously part of your problem.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!