2.23. Dekorátory¶
Dekorátor je kus syntaxe, který obaluje funkci (nebo metodu) do jiné funkce. Obal může přidat chování před a po původním volání, nahradit návratovou hodnotu nebo připojit metadata. Tvar je:
@wrapper
def f():
...
Řádek @wrapper je ekvivalentní f = wrapper(f) – funkce f se sestaví normálně, pak se předá wrapper a výsledek se znovu naváže na jméno f.
Dekorátor přijme funkci a vrátí novou funkci.¶
2.23.1. Vestavěné dekorátory metod¶
Několik dekorátorů je součástí Pythonu a používá se uvnitř těl tříd.
2.23.1.1. @property¶
Promění metodu v vypočítaný atribut. Volající k němu přistupuje, jako by to byl obyčejný atribut (bez závorek), ale při každém čtení se spustí metoda:
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
Použijte jej, když atribut, který vypadá jednoduše, za sebou potřebuje drobný výpočet. Pokud je práce náročná, dejte přednost běžné metodě – volající neočekávají, že čtení atributu bude pomalé.
2.23.1.2. @classmethod¶
Definuje metodu, která jako svůj první argument dostává třídu místo instance. První parametr se konvenčně pojmenovává 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()
Metody třídy jsou standardní způsob, jak poskytnout alternativní konstruktory – tovární funkce, které vracejí instanci sestavenou nestandardním způsobem.
2.23.1.3. @staticmethod¶
Definuje metodu, která nedostává ani instanci, ani třídu – je to prostě obyčejná funkce, která žije v jmenném prostoru třídy z organizačních důvodů:
class Temperature:
@staticmethod
def c_to_f(c):
return c * 9 / 5 + 32
Temperature.c_to_f(100) # 212.0
Používejte ji střídmě; pokud funkce opravdu nemá nic společného se stavem třídy, je obvykle čistší obyčejná funkce na úrovni modulu.
2.23.2. Napsání vlastního dekorátoru¶
Dekorátor je funkce, která přijme funkci a vrátí funkci. Minimální tvar:
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)
Výstup:
calling add
wrapper uzavírá nad func a vše do něj předává. *args / **kwargs mu umožňuje fungovat na jakékoli funkci, nejen na dvouargumentových. Tento vzor je základem propracovanějších dekorátorů (měření času, kešování, opakování při selhání), ale jádro je vždy stejné: přijmout funkci, vrátit funkci.