„Python“ dekoratoriai: kaip jį naudoti ir kodėl?

Dekoratorius perima funkciją, prideda tam tikrą funkciją ir grąžina ją. Šioje pamokoje sužinosite, kaip galite sukurti dekoratorių ir kodėl turėtumėte jį naudoti.

Dekoratoriai „Python“

„Python“ turi įdomią funkciją, vadinamą dekoratoriais, kad pridėtų funkcijų prie esamo kodo.

Tai taip pat vadinama metaprogramavimu, nes dalis programos bando modifikuoti kitą programos dalį kompiliavimo metu.

Privalomos sąlygos mokytis dekoratorių

Norėdami suprasti apie dekoratorius, pirmiausia turime žinoti keletą pagrindinių „Python“ dalykų.

Turime būti patenkinti tuo, kad viskas „Python“ (taip! Net klasės) yra objektai. Mūsų apibrėžti pavadinimai yra tiesiog identifikatoriai, susieti su šiais objektais. Funkcijos nėra išimtis, jos taip pat yra objektai (su atributais). Į tą patį funkcijos objektą galima susieti įvairius skirtingus pavadinimus.

Štai pavyzdys.

 def first(msg): print(msg) first("Hello") second = first second("Hello")

Rezultatas

 Sveiki sveiki

Kai paleidžiate kodą, abi funkcijos firstir secondduoda tą patį išėjimą. Čia pavadinimai firstir secondnuoroda į tą patį funkcijos objektą.

Dabar viskas pradeda keistis.

Funkcijos gali būti perduotos kaip argumentai kitai funkcijai.

Jei turite naudojamų funkcijų, pavyzdžiui map, filterir reducePython, tada jūs jau žinote apie tai.

Tokios funkcijos, kurios kitas funkcijas laiko argumentais, dar vadinamos aukštesnės eilės funkcijomis . Štai tokios funkcijos pavyzdys.

 def inc(x): return x + 1 def dec(x): return x - 1 def operate(func, x): result = func(x) return result

Funkciją iškviečiame taip.

 >>> operate(inc,3) 4 >>> operate(dec,3) 2

Be to, funkcija gali grąžinti kitą funkciją.

 def is_called(): def is_returned(): print("Hello") return is_returned new = is_called() # Outputs "Hello" new()

Rezultatas

 Sveiki

Čia is_returned()yra įdėta funkcija, kuri yra apibrėžta ir grąžinama kiekvieną kartą, kai skambiname is_called().

Galiausiai turime žinoti apie „Python“ uždarymus.

Grįžimas prie dekoratorių

Funkcijos ir metodai vadinami skambinamaisiais, nes juos galima vadinti.

Tiesą sakant, bet kuris objektas, įgyvendinantis specialųjį __call__()metodą, vadinamas iškviečiamuoju. Taigi, paprasčiausia prasme, dekoratorius yra skambinamasis, kuris grąžina skambinamąjį.

Iš esmės dekoratorius priima funkciją, prideda tam tikrą funkciją ir grąžina ją.

 def make_pretty(func): def inner(): print("I got decorated") func() return inner def ordinary(): print("I am ordinary")

Kai paleidžiate šiuos kodus su apvalkalu,

 >>> ordinary() I am ordinary >>> # let's decorate this ordinary function >>> pretty = make_pretty(ordinary) >>> pretty() I got decorated I am ordinary

Aukščiau pateiktame pavyzdyje make_pretty()yra dekoratorius. Priskyrimo etape:

 pretty = make_pretty(ordinary)

Funkcija ordinary()buvo papuošta, o grąžintai funkcijai suteiktas pavadinimas pretty.

Galime pastebėti, kad dekoratoriaus funkcija pridėjo keletą naujų funkcijų prie pradinės funkcijos. Tai panašu į dovanos pakavimą. Dekoratorius veikia kaip apvalkalas. Papuošto objekto pobūdis (faktinė dovana viduje) nesikeičia. Bet dabar jis atrodo gana (nes jis buvo dekoruotas).

Paprastai mes dekoruojame funkciją ir priskiriame ją kaip

 ordinary = make_pretty(ordinary).

Tai yra įprasta konstrukcija, todėl „Python“ turi sintaksę, kad tai supaprastintų.

@Simbolį galime naudoti kartu su dekoratoriaus funkcijos pavadinimu ir pastatyti jį virš dekoruojamos funkcijos apibrėžimo. Pavyzdžiui,

 @make_pretty def ordinary(): print("I am ordinary")

yra lygiavertis

 def ordinary(): print("I am ordinary") ordinary = make_pretty(ordinary)

Tai tik sintaksinis cukrus dekoratoriams įgyvendinti.

Funkcijų dekoravimas parametrais

Minėtas dekoratorius buvo paprastas ir jis veikė tik su funkcijomis, neturinčiomis jokių parametrų. Kas būtų, jei turėtume funkcijas, kurios atsižvelgtų į tokius parametrus:

 def divide(a, b): return a/b

Ši funkcija turi du parametrus: a ir b. Mes žinome, kad tai duos klaidą, jei b įrašysime kaip 0.

 >>> divide(2,5) 0.4 >>> divide(2,0) Traceback (most recent call last):… ZeroDivisionError: division by zero

Dabar padarysime dekoratorių, kad patikrintume, ar šis atvejis sukels klaidą.

 def smart_divide(func): def inner(a, b): print("I am going to divide", a, "and", b) if b == 0: print("Whoops! cannot divide") return return func(a, b) return inner @smart_divide def divide(a, b): print(a/b)

Šis naujas diegimas bus grąžintas, Nonejei atsiras klaidos sąlyga.

 >>> divide(2,5) I am going to divide 2 and 5 0.4 >>> divide(2,0) I am going to divide 2 and 0 Whoops! cannot divide

Tokiu būdu galime papuošti funkcijas, kurios ima parametrus.

Dėmesingas stebėtojas pastebės, inner()kad dekoratoriaus viduje įdėtos funkcijos parametrai yra tokie patys kaip jo dekoruojamų funkcijų parametrai. Atsižvelgdami į tai, dabar galime pagaminti bendruosius dekoratorius, kurie dirba su bet kokiu parametru.

„Python“ ši magija daroma kaip function(*args, **kwargs). Tokiu būdu argsbus pozicinių argumentų paketas ir kwargsraktinių žodžių argumentų žodynas. Tokio dekoratoriaus pavyzdys bus:

 def works_for_all(func): def inner(*args, **kwargs): print("I can decorate any function") return func(*args, **kwargs) return inner

Grandinių dekoratoriai „Python“

Keli dekoratoriai gali būti sujungti „Python“.

Tai reiškia, kad funkcija gali būti dekoruota kelis kartus su skirtingais (arba tais pačiais) dekoratoriais. Papuošėjus paprasčiausiai pastatome virš norimos funkcijos.

 def star(func): def inner(*args, **kwargs): print("*" * 30) func(*args, **kwargs) print("*" * 30) return inner def percent(func): def inner(*args, **kwargs): print("%" * 30) func(*args, **kwargs) print("%" * 30) return inner @star @percent def printer(msg): print(msg) printer("Hello")

Rezultatas

 ******************************* %%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%% Sveiki %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ********* *********************

Aukščiau pateikta sintaksė,

 @star @percent def printer(msg): print(msg)

yra lygiavertis

 def printer(msg): print(msg) printer = star(percent(printer))

Svarba yra tvarka, kuria mes dekoratorius dekoruojame. Jei būtume pakeitę tvarką,

 @percent @star def printer(msg): print(msg)

Rezultatas būtų:

 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ********************* ********** Sveiki ****************************** %%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%

Įdomios straipsniai...