2.23. Dekoratori¶
Dekorator je dio sintakse koji omata funkciju (ili metodu) u drugu funkciju. Omotač može dodati ponašanje prije i nakon izvornog poziva, zamijeniti povratnu vrijednost ili pridodati metapodatke. Oblik je:
@wrapper
def f():
...
Redak @wrapper ekvivalentan je s f = wrapper(f) – funkcija f se gradi normalno, zatim predaje funkciji wrapper, a rezultat se ponovno veže na ime f.
Dekorator prima funkciju i vraća novu funkciju.¶
2.23.1. Ugrađeni dekoratori metoda¶
Nekoliko dekoratora dolazi s Pythonom i koristi se unutar tijela klasa.
2.23.1.1. @property¶
Pretvara metodu u izračunati atribut. Pozivatelj mu pristupa kao da je običan atribut (bez zagrada), no pri svakom čitanju izvršava se 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
Koristi ga kad atribut koji izgleda jednostavno iza sebe treba sitan izračun. Ako je posao skup, radije koristi običnu metodu – pozivatelji ne očekuju da je čitanje atributa sporo.
2.23.1.2. @classmethod¶
Definira metodu koja kao prvi argument prima klasu umjesto instance. Prvi parametar se konvencionalno imenuje 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()
Metode klase standardni su način pružanja alternativnih konstruktora – tvorničkih funkcija koje vraćaju instancu izgrađenu na nezadani način.
2.23.1.3. @staticmethod¶
Definira metodu koja ne prima ni instancu ni klasu – to je samo obična funkcija koja iz organizacijskih razloga živi u imenskom prostoru klase:
class Temperature:
@staticmethod
def c_to_f(c):
return c * 9 / 5 + 32
Temperature.c_to_f(100) # 212.0
Koristi ga štedljivo; ako funkcija stvarno nema nikakve veze sa stanjem klase, obična funkcija na razini modula obično je čišća.
2.23.2. Pisanje vlastitog dekoratora¶
Dekorator je funkcija koja prima funkciju i vraća funkciju. Minimalni oblik:
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)
Izlaz:
calling add
wrapper se zatvara nad func i sve mu prosljeđuje. *args / **kwargs omogućuje mu rad s bilo kojom funkcijom, ne samo s onima s dva argumenta. Ovaj obrazac temelj je razrađenijih dekoratora (mjerenje vremena, predmemoriranje, ponovni pokušaj pri neuspjehu), no srž je uvijek ista: primi funkciju, vrati funkciju.