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 first
un second
dod vienu un to pašu izvadi. Šeit nosaukumi first
un second
atsauce 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
, filter
un reduce
Python, 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, None
ja 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ā args
būs pozīciju argumentu kopa un kwargs
atslē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 ****************************** %%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%