Python dekoratori: kā to izmantot un kāpēc?

Dekorators uzņem funkciju, pievieno kādu funkcionalitāti un atdod to. Šajā apmācībā jūs uzzināsiet, kā jūs varat izveidot dekoratoru un kāpēc tas jāizmanto.

Dekoratori Python

Python ir interesanta funkcija, ko sauc par dekoratoriem, lai pievienotu funkcionalitāti esošam kodam.

To sauc arī par metaprogrammēšanu, jo daļa programmas kompilēšanas laikā mēģina modificēt citu programmas daļu.

Priekšnoteikumi dekoratoru apguvei

Lai saprastu par dekoratoriem, mums vispirms ir jāzina dažas pamata lietas Python.

Mums jābūt apmierinātiem ar to, ka viss Python (Jā! Pat klases) ir objekti. Nosaukumi, kurus mēs definējam, ir vienkārši identifikatori, kas saistīti ar šiem objektiem. Funkcijas nav izņēmums, tās ir arī objekti (ar atribūtiem). Tajā pašā funkcijas objektā var būt saistīti dažādi nosaukumi.

Šeit ir piemērs.

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

Rezultāts

 Sveiki sveiki

Palaidot kodu, abas funkcijas firstun seconddod vienu un to pašu izvadi. Šeit nosaukumi firstun secondatsauce uz to pašu funkcijas objektu.

Tagad lietas sāk kļūt dīvainākas.

Funkcijas var pārsūtīt kā argumentus citai funkcijai.

Ja esat lietojis funkcijas, piemēram map, filterun reducePython, tad jūs jau zināt par to.

Šādas funkcijas, kas citas funkcijas uzskata par argumentiem, sauc arī par augstākas kārtas funkcijām . Šeit ir šādas funkcijas piemērs.

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

Funkciju mēs izsaucam šādi.

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

Turklāt funkcija var atgriezt citu funkciju.

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

Rezultāts

 Sveiki

Šeit is_returned()ir ligzdota funkcija, kas tiek definēta un atgriezta katru reizi, kad izsaucam is_called().

Visbeidzot, mums jāzina par Python slēgšanu.

Atgriešanās pie dekoratoriem

Funkcijas un metodes sauc par izsaucamām, jo tās var izsaukt.

Faktiski jebkurš objekts, kas ievieš īpašo __call__()metodi, tiek saukts par izsaucamu. Tātad, visprecīzākajā nozīmē, dekorators ir izsaucams, kas atgriež izsaucamo.

Būtībā dekorators uzņem funkciju, pievieno kādu funkcionalitāti un atdod to.

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

Palaižot šādus kodus čaulā,

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

Iepriekš redzamajā piemērā make_pretty()ir dekorators. Piešķiršanas solī:

 pretty = make_pretty(ordinary)

Funkcija ordinary()tika dekorēta, un atgrieztajai funkcijai tika piešķirts nosaukums pretty.

Mēs varam redzēt, ka dekoratora funkcija sākotnējai funkcijai pievienoja dažas jaunas funkcijas. Tas ir līdzīgi kā dāvanas iesaiņošana. Dekorators darbojas kā iesaiņotājs. Izrotātā priekšmeta daba (faktiskā dāvana iekšpusē) nemainās. Bet tagad tas izskatās diezgan (jo tas tika dekorēts).

Parasti mēs izrotājam funkciju un atkārtoti piešķiram to kā

 ordinary = make_pretty(ordinary).

Šī ir izplatīta konstrukcija, un šī iemesla dēļ Python ir sintakse, lai to vienkāršotu.

Mēs varam izmantot @simbolu kopā ar dekoratora funkcijas nosaukumu un novietot to virs dekorējamās funkcijas definīcijas. Piemēram,

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

ir ekvivalents

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

Tas ir tikai sintaktiskais cukurs dekoratoru ieviešanai.

Funkciju dekorēšana ar parametriem

Iepriekš minētais dekorētājs bija vienkāršs, un tas darbojās tikai ar funkcijām, kurām nebija parametru. Ko darīt, ja mums būtu funkcijas, kas ņemtu tādus parametrus kā:

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

Šai funkcijai ir divi parametri - a un b. Mēs zinām, ka tas radīs kļūdu, ja mēs ieskaitīsim b kā 0.

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

Tagad izveidosim dekoratoru, lai pārbaudītu šo gadījumu, kas izraisīs kļūdu.

 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)

Šī jaunā ieviešana tiks atgriezta, Noneja radīsies kļūdas nosacījums.

 >>> 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

Tādā veidā mēs varam izrotāt funkcijas, kas ņem parametrus.

Dedzīgs novērotājs pamanīs, ka ligzdotās inner()funkcijas parametri dekoratora iekšienē ir tādi paši kā to rotāto funkciju parametri. Ņemot to vērā, tagad mēs varam izgatavot vispārīgus dekoratorus, kas darbojas ar jebkuru parametru skaitu.

Pitonā šī burvība tiek veikta kā function(*args, **kwargs). Tādā veidā argsbūs pozīciju argumentu kopa un kwargsatslēgvārdu argumentu vārdnīca. Šāda dekoratora piemērs būs:

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

Ķēdes dekoratori Python

Python var būt pieķēdēti vairāki dekoratori.

Tas nozīmē, ka funkciju var dekorēt vairākas reizes ar dažādiem (vai tiem pašiem) dekoratoriem. Dekoratorus mēs vienkārši novietojam virs vēlamās funkcijas.

 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")

Rezultāts

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

Iepriekš minētā sintakse

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

ir ekvivalents

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

Kārtībai, kādā mēs ķēdājam dekorētājus, ir nozīme. Ja mēs būtu mainījuši pasūtījumu kā,

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

Rezultāts būtu:

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

Interesanti raksti...