Pythoni sisekujundajad: kuidas seda kasutada ja miks?

Kaunistaja võtab sisse funktsiooni, lisab funktsionaalsuse ja tagastab selle. Selles õpetuses saate teada, kuidas saate kujundaja luua ja miks peaksite seda kasutama.

Kaunistajad Pythonis

Pythonil on olemasolevale koodile funktsionaalsuse lisamiseks huvitav funktsioon, mida nimetatakse dekoraatoriteks .

Seda nimetatakse ka metaprogrammeerimiseks, kuna osa programmist proovib kompileerimise ajal muuta mõnda teist programmi osa.

Eeldused dekoraatorite õppimiseks

Kaunistajate mõistmiseks peame kõigepealt teadma Pythonis mõnda põhiasja.

Peame olema rahul sellega, et kõik Pythonis (jah! Isegi klassid) on objektid. Meie määratletud nimed on lihtsalt nende objektidega seotud identifikaatorid. Funktsioonid pole erandid, nad on ka objektid (koos atribuutidega). Sama funktsiooni objektiga saab siduda erinevaid nimesid.

Siin on näide.

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

Väljund

 Tere Tere

Kui teil tekib koodi, nii funktsioone firstja secondanda sama tulemuse. Siin nimed firstja secondviitavad samale funktsiooni objektile.

Nüüd hakkavad asjad veidramaks minema.

Funktsioonid saab argumendina edastada teisele funktsioonile.

Kui olete kasutanud funktsioone nagu map, filterja reducePython, siis sa juba tead seda.

Selliseid funktsioone, mis võtavad argumentidena muid funktsioone, nimetatakse ka kõrgema järgu funktsioonideks . Siin on näide sellisest funktsioonist.

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

Funktsiooni kutsume järgmiselt.

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

Lisaks võib funktsioon tagastada teise funktsiooni.

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

Väljund

 Tere

Siin is_returned()on pesastatud funktsioon, mis määratletakse ja tagastatakse iga kord, kui helistame is_called().

Lõpuks peame teadma Pythoni sulgemiste kohta.

Tagasi dekoraatorite juurde

Funktsioone ja meetodeid nimetatakse helistatavateks, kuna neid saab kutsuda.

Tegelikult __call__()nimetatakse kõiki erimeetodit rakendavaid objekte helistatavaks. Niisiis on sisekujundaja kõige põhilisemas mõttes helistatav, mis tagastab helistatava.

Põhimõtteliselt võtab dekoraator funktsiooni sisse, lisab funktsionaalsuse ja tagastab selle.

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

Järgmiste koodide käivitamisel kestas,

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

Ülaltoodud näites make_pretty()on dekoraator. Määramise etapis:

 pretty = make_pretty(ordinary)

Funktsioon ordinary()sai kaunistatud ja tagastatud funktsioonile anti nimi pretty.

Näeme, et dekoraatori funktsioon lisas algsele funktsioonile mõned uued funktsioonid. See sarnaneb kingituse pakkimisega. Kaunistaja toimib ümbrisena. Kaunistatud eseme olemus (tegelik kingitus sees) ei muutu. Kuid nüüd tundub see ilus (kuna see sai kaunistatud).

Üldiselt kaunistame funktsiooni ja määrame selle ümber,

 ordinary = make_pretty(ordinary).

See on tavaline konstruktsioon ja seetõttu on Pythonis selle lihtsustamiseks süntaks.

Võime kasutada @sümbolit koos dekoraatori funktsiooni nimega ja asetada selle kaunistatava funktsiooni definitsiooni kohale. Näiteks,

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

on samaväärne

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

See on dekoraatorite rakendamiseks lihtsalt süntaktiline suhkur.

Funktsioonide kaunistamine parameetritega

Ülaltoodud dekoraator oli lihtne ja see töötas ainult funktsioonidega, millel puudusid parameetrid. Mis oleks, kui meil oleks funktsioone, mis võtaksid sisse sellised parameetrid nagu:

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

Sellel funktsioonil on kaks parameetrit, a ja b. Me teame, et see annab vea, kui edastame b väärtuseks 0.

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

Nüüd teeme dekoraatori, et kontrollida seda juhtumit, mis põhjustab vea.

 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)

See uus juurutus naaseb Noneveatingimuse ilmnemisel.

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

Sel viisil saame kaunistada funktsioone, mis võtavad parameetreid.

Terav vaatleja märkab, et inner()sisekujunduses oleva pesastatud funktsiooni parameetrid on samad kui kaunistatud funktsioonide parameetrid. Seda arvesse võttes saame nüüd valmistada üldised dekoraatorid, mis töötavad mis tahes arvu parameetritega.

Pythonis tehakse seda maagiat nii function(*args, **kwargs). Sel moel argson see positsiooniliste argumentide kogum ja kwargsmärksõnade argumentide sõnastik. Sellise dekoraatori näide on:

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

Aheldavad dekoraatorid Pythonis

Pythonis saab aheldada mitu sisekujundajat.

See tähendab, et funktsiooni saab mitu korda kaunistada erinevate (või samade) dekoraatoritega. Me lihtsalt paneme kaunistajad soovitud funktsiooni kohale.

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

Väljund

 ******************************* %%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%% Tere %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ********* *********************

Ülaltoodud süntaks

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

on samaväärne

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

Tähtsus on selles, millises järjekorras me kaunistajad aheldame. Kui me oleksime tellimuse tühistanud,

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

Väljund oleks:

 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ********************* ********** Tere ****************************** %%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%

Huvitavad Artiklid...