#python #python-decorators
#python #python-декораторы
Вопрос:
Рассмотрим следующий код:
class C:
def decorator(self):
print(self)
def inner(*args):
return self(*args)
return inner
@decorator
def decorated(self):
...
if __name__ == '__main__':
c = C()
c.decorator() # 1
c.decorated() #2
Результат таков:
<function C.decorated at 0x1121cd9d8>
<__main__.C object at 0x111f5a8d0>
- Когда
decorator
функция вызывается как обычная функция класса, первым аргументом, который она получает, является экземпляр класса. - Однако при
decorated
вызове иdecorator
использовании функции в качестве декоратора первым аргументом являетсяdecorated
функция;decorator
теперь функция ведет себя практически так же, как обычная функция, определенная вне класса.
Интуитивно, поскольку decorator
функция определяется как функция внутри класса без @staticmethod
@classmethod
декоратора or , я подумал, что первым аргументом, который он получает, всегда должен быть экземпляр класса. Однако это было не так.
Я не часто вижу этот шаблон кодирования, но широко ли используется этот шаблон кодирования? Каковы возможные подводные камни при использовании этого шаблона кодирования?
Ответ №1:
Я внес небольшое изменение в ваш код и попытался объяснить, что происходит в комментариях:
class C:
def decorator(self, count=[0]):
print(count, ":", self)
count[0] = 1
def inner(*args):
return self(*args)
return inner
@decorator
def decorated(self):
print(self)
if __name__ == '__main__':
c = C() #0 Applies the decorator like
# decorated = decorator(decorated)
# Above, self equals decorated function, and gets printed
# inside decorator function.
# The decorated function is now a function that returns decorated(*args), actually None, but prints self, at call moment (not now).
c.decorator() #1 normal bound method call, self is c
print("[2] : ", end="") # for visual reference
c.decorated() #2 calls C.decorated(c) so now self is c again and decorated is the result of decorated(c) that returns None but prints self (equals c), with no print from the decorator bound method, that does not run.
Выводит:
[0] : <function C.decorated at 0x7f26945b4ee0>
[1] : <__main__.C object at 0x7f26945bddc0>
[2] : <__main__.C object at 0x7f26945bddc0>
Я думаю, что это использование немного сбивает с толку, поэтому, если у вас нет конкретной причины для этого… Однако я видел некоторый продвинутый код с декораторами или метаклассами, который может быть трудным для понимания. Это всегда вопрос того, действительно ли нужно что-то стоящее. Я предлагаю вам поискать типичные способы использования декоратора и декоратора класса. Редко встречающийся внешний вид отличается от широко используемого.
Ответ №2:
Кажется, что «проблема» на самом деле заключается в инициализации
class C:
def decorator(self):
print(self)
def inner(*args):
return self(*args)
return inner
@decorator
def decorated(self):
pass
if __name__ == '__main__':
c = C()
#c.decorator() # 1
#c.decorated() #2
python test.py
<function C.decorated at 0x00000289DD5BE160>
Итак … при инициализации класса с декорированными функциями сначала он изменяет функцию (для запуска декоратора вместо декорированного).
Вероятно, есть какая-то документация, которую можно прочитать. Я никогда не использовал декораторы внутри класса, только отдельно.