Объяснение класса декоратора в python

При чтении некоторых модулей python я столкнулся с этим классом декоратора:

# this decorator lets me use methods as both static and instance methods class omnimethod(object): def __init__(self, func): self.func = func def __get__(self, instance, owner): return functools.partial(self.func, instance) 

То, что я знаю о декораторах, заключается в том, что они могут расширить функциональность (например, для функции). Может ли кто-нибудь быть таким добрым и объяснить мне, почему класс выше полезен и как он работает ?

Он используется в коде таким образом:

 @omnimethod: def some_function(...): pass 

Другой вопрос:

 I encountered this piece of code in the same file: @property def some_other_function(...): pass 

@property не определен нигде в файле. Это какой-то стандартный декоратор? Если да, что он делает? Google не мог помочь мне в этом деле.

Кстати, вот источник, где я нашел код: http://code.xster.net/pygeocoder/src/c9460febdbd1/pygeocoder.py

  • Как установить gevent в Windows?
  • float64 с pandas to_csv
  • PyGame забивает Linux?
  • Преобразование между datetime, Timestamp и datetime64
  • Помогите мне разобраться в обходном пути без использования рекурсии
  • Python: импорт «файла импорта»
  • Python - как выполнять команды оболочки с помощью трубы?
  • Построение эллипсоида с помощью Matplotlib
  • 2 Solutions collect form web for “Объяснение класса декоратора в python”

    этот омниметод очень умный. Он использует некоторые очень тонкие трюки, чтобы сделать это. Начнем с самого начала.

    Вы, наверное, уже знаете, что синтаксис декоратора – это просто сахар для применения функции, то есть:

     @somedecorator def somefunc(...): pass # is the same thing as def somefunc(...): pass somefunc = somedecorator(somefunc) 

    поэтому somefunc фактически является экземпляром omnimethod , а не функцией, которая была определена. что интересно, так это то, что omnimethod также реализует интерфейс descriptor . Если атрибут класса определяет метод __get__ , тогда всякий раз, когда упоминается этот атрибут, интерпретатор вместо этого вызывает __get__ на этом объекте и возвращает это вместо того, чтобы возвращать сам атрибут.

    метод __get__ всегда вызывается с экземпляром как первый аргумент, а класс этого экземпляра – вторым аргументом. Если атрибут был фактически просмотрен из самого класса, то экземпляр будет None .

    Последний бит обмана – functools.partial , который является способом python функции currying . когда вы используете partial , вы передаете ему функцию и некоторые аргументы и возвращает новую функцию, которая при вызове вызовет исходную функцию с исходными аргументами в дополнение к тем аргументам, которые вы передали позже. omnimethod использует эту технику для заполнения параметра self для функции, которую он обертывает.

    Вот как это выглядит. регулярный метод можно вызывать, когда вы читаете его из экземпляра, но вы не можете использовать его из самого класса. вы получаете несвязанный TypeError

     >>> class Foo(object): ... def bar(self, baz): ... print self, baz ... >>> f = Foo() >>> f.bar('apples') <__main__.Foo object at 0x7fe81ab52f90> apples >>> Foo.bar('quux') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method bar() must be called with Foo instance as first argument (got str instance instead) >>> Foo.bar(None, 'quux') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method bar() must be called with Foo instance as first argument (got NoneType instance instead) >>> 

    Python предоставляет класс classmethod bultin decorator (а также staticmethod , но staticmethod , что), который позволит вам использовать его на уровне класса, но он никогда не увидит экземпляр. он всегда получает класс, как первый аргумент.

     >>> class Foo(object): ... @classmethod ... def bar(cls, baz): ... print cls, baz ... >>> f = Foo() >>> Foo.bar('abc') <class '__main__.Foo'> abc >>> f.bar('def') <class '__main__.Foo'> def >>> 

    Немного сообразительности, omnimethod дает вам немного того и другого.

     >>> class Foo(object): ... @omnimethod ... def bar(self, baz): ... print self, baz ... >>> f = Foo() >>> Foo.bar('bananas') None bananas >>> f.bar('apples') <__main__.Foo object at 0x7fe81ab52f90> apples >>> 

    omnimethod делает то, что говорится в комментарии; он позволит вам вызвать some_function как «статическую функцию» в классе или как функцию на экземпляре класса. @property – стандартный декоратор (см. документы python ), который предоставляет функцию таким образом, чтобы она выглядела как простая переменная экземпляра.

     class B: @omnimethod def test(self): print 1 @property def prop(self): return 2 >>> b = B() >>> b.test() 1 >>> B.test() 1 >>> b.prop 2 
    Python - лучший язык программирования в мире.