Подход декоратора не работает, потому что декоратор вызывается при создании класса, а не при создании экземпляра.Когда вы говорите
class Foo(object):
@some_decorator
def bar(self, *args, **kwargs):
# etc etc
, тогда при создании класса Foo будет вызываться some_decorator
, и ему будет передан несвязанный метод, а не связанный метод экземпляра.Вот почему 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
... но весь смысл вашегоСуть в том, что никто этого не делает!Механизм обратного вызова события вызывает непосредственный вызов экземпляра listen
, потому что это то, что он получает, и экземпляр listen
вызывает несвязанный метод, который он сжимал при создании.listen.__get__
никогда не будет вызван, а параметр _self
никогда не будет установлен должным образом ... , если только вы сами явно не обращаетесь к self.some_method
, как я делал в методе __init__
выше.Тогда listen.__get__
будет вызываться при создании экземпляра и _self
будет установлен правильно.
Проблема в том, что (а) это ужасный, ужасный взлом и (б) если вы попытаетесь создать два экземпляра Foo
, тогда второй перезапишет _self
, установленный первым, потому что все еще создается только один listen
объект, который связан с классом, а не с экземпляром.Если вы когда-либо используете только один экземпляр Foo
, то все в порядке, но если вам нужно, чтобы событие вызывало два разных Foo
, вам просто нужно будет использовать регистрацию вашего события "старого стиля".
Версия TL, DR: декорирование метода украшает несвязанный метод класса, тогда как вы хотите, чтобы ваш менеджер событий получил метод bound экземпляра.