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 позволяют ему работать с любой функцией, а не только с двухаргументными. Этот шаблон является основой для более сложных декораторов (замер времени, кэширование, повтор при сбое), но суть всегда одна и та же: принять функцию, вернуть функцию.