Dekorátory
# předpokládáme existenci dekorátoru @vypis_cas
def uvar_kafe():
print("Vařím kafe")
@vypis_cas
def natoc_pivo():
print("Točím pivo")
uvar_kafe() # Vařím kafe
natoc_pivo() # 2020-09-08 10:50:47: Točím pivo
Možnosti použití
# (podmínečné) nahrazení původní funkce jinou
@deaktivuj_pri_testu
def posli_penize(kolik, komu):
print(f"Posílám {kolik} peněz {komu}")
@deaktivuj_pri_testu
def posli_sms(text, komu):
print(f"Posílám SMS {text} na číslo {komu}")
# přidání chování před/za kód původní funkce
@timer
def stahni_data_z_databaze():
print("Stahuji seznam knih")
@timer
def nahraj_na_youtube():
print("Nahrávám video")
@zkontroluj_opravneni
def zmenit_heslo(kdo, pro_koho, heslo):
print(f"{kdo} mění heslo pro uživatele"
f"{pro_koho} na {heslo}")
@zkontroluj_opravneni
def nahrat_obrazek(kdo, pro_koho, obrazek):
print(f"{kdo} nahrává obrázek {obrazek}"
f"pro uživatele {pro_koho}")
# zapsání do nějaké evidence
import atexit
@atexit.register
def rozluc_se():
print("Děkujeme za použití programu!")
@atexit.register
def odeslat_data_do_nsa():
# print("Nic nevypisuj, nebo to poznají!")
pass
app = Flask("moje-stranka")
@app.route("/")
def uvitaci_stranka():
return "Ahoj, vítám vás na svém webu!"
@app.route("/tajna-stranka")
def tajna_stranka():
return "Tajné heslo je: PythonRulez"
class DataSet:
def __init__(self, sequence_of_numbers):
self._data = sequence_of_numbers
@functools.cached_property
def stdev(self):
return statistics.stdev(self._data)
@functools.cached_property
def variance(self):
return statistics.variance(self._data)
@click.command()
@click.option("--pocet", default=1)
@click.argument("jmeno")
def pozdrav(pocet, jmeno):
for x in range(pocet):
print(f"Ahoj {jmeno}")
@click.command()
def rozluc_se():
print(f"Měj se fajn")
Jak vytvořit dekorátor?
def vypis_cas(puvodni_fce):
def nahradni_fce():
print(datetime.now(), end=": ")
return puvodni_fce()
return nahradni_fce
Dekorátory jsou (typicky) funkce, které obalují jiné funkce, čímž mohou přidávat nebo měnit jejich chování.
Originální funkci dostávají jako parametr a místo ní vrací jinou, která uvnitř používá tu původní.
Jak vytvořit dekorátor?
... správně
import functools
def vypis_cas(puvodni_fce):
@functools.wraps(puvodni_fce)
def nahradni_fce(*args, **kwargs):
print(datetime.now(), end=": ")
return puvodni_fce(*args, **kwargs)
return nahradni_fce
BONUS
Implementace použitých dekorátorů
testujeme = True
def deaktivuj_pri_testu(puvodni_fce):
@functools.wraps(puvodni_fce)
def nahradni_fce(*args, **kwargs):
if testujeme:
print(f"Funkce {puvodni_fce.__name__} "
"byla deaktivována kvůli "
"testovacímu režimu")
else:
return puvodni_fce(*args, **kwargs)
return nahradni_fce
def timer(puvodni_fce):
@functools.wraps(puvodni_fce)
def nahradni_fce(*args, **kwargs):
start = time.perf_counter_ns()
vysledek = puvodni_fce(*args, **kwargs)
konec = time.perf_counter_ns()
print(f"Funkce trvala {konec - start} ns")
return vysledek
return nahradni_fce
def zkontroluj_opravneni(puvodni_fce):
@functools.wraps(puvodni_fce)
def nahradni_fce(kdo, pro_koho, *args, **kwargs):
if kdo == pro_koho or kdo == "admin":
return puvodni_fce(kdo, pro_koho,
*args, **kwargs)
else:
raise ValueError(f"Uživatel {kdo} není "
f"oprávněn provést "
f"tuto operaci")
return nahradni_fce
Dekorátory
By Tomáš Bedřich
Dekorátory
- 1,275