2.23. Декоратори¶
Декоратор – це синтаксична конструкція, яка загортає функцію (або метод) в іншу функцію. Обгортка може додавати поведінку до і після оригінального виклику, замінювати значення, що повертається, або прикріплювати метадані. Синтаксис:
@wrapper
def f():
...
Рядок @wrapper еквівалентний f = wrapper(f) – функція f будується звичайним чином, потім передається до wrapper, а результат знову прив’язується до імені f.
Декоратор приймає функцію та повертає нову функцію.¶
2.23.1. Вбудовані декоратори методів¶
Кілька декораторів входять до складу Python і використовуються всередині тіл класів.
2.23.1.1. @property¶
Перетворює метод на обчислюваний атрибут. Той, хто викликає, звертається до нього як до звичайного атрибута (без дужок), але при кожному читанні виконується метод:
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return 3.14159 * self.radius * self.radius
c = Circle(5)
print(c.area) # 78.53975 -- no parentheses
Використовуйте його, коли атрибут, що виглядає простим, потребує невеликого обчислення. Якщо операція ресурсомістка, надайте перевагу звичайному методу – той, хто викликає, не очікує, що читання атрибутів буде повільним.
2.23.1.2. @classmethod¶
Визначає метод, який отримує клас як перший аргумент замість екземпляра. Перший параметр традиційно називають cls:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def origin(cls):
return cls(0, 0)
p = Point.origin()
Методи класу є стандартним способом надання альтернативних конструкторів – фабричних функцій, які повертають екземпляр, побудований нестандартним способом.
2.23.1.3. @staticmethod¶
Визначає метод, який не отримує ані екземпляр, ані клас – це просто звичайна функція, що живе в просторі імен класу з організаційних причин:
class Temperature:
@staticmethod
def c_to_f(c):
return c * 9 / 5 + 32
Temperature.c_to_f(100) # 212.0
Використовуйте його помірно; якщо функція дійсно не має нічого спільного зі станом класу, звичайна функція на рівні модуля зазвичай чистіша.
2.23.2. Написання власного декоратора¶
Декоратор – це функція, яка приймає функцію та повертає функцію. Мінімальний шаблон:
def log_calls(func):
def wrapper(*args, **kwargs):
print("calling", func.__name__)
return func(*args, **kwargs)
return wrapper
@log_calls
def add(a, b):
return a + b
add(2, 3)
Виведення:
calling add
wrapper замикається над func і пересилає все до нього. *args / **kwargs дозволяє йому працювати з будь-якою функцією, а не лише з функціями з двома аргументами. Цей шаблон є основою більш складних декораторів (вимірювання часу, кешування, повтор при помилці), але суть завжди одна: отримати функцію на вході, повернути функцію на виході.