Python dekorateri - je li to što?

Dekorater je predložak dizajniran za povezivanje dodatnog ponašanja s objektom. Koristi se u mnogim jezicima OOP-a: Java, C #, PHP, JS. Python nije iznimka. Zadatak dekoratera može se opisati u sljedećem primjeru. Postoji objekt koji obavlja neku funkciju, za vrijeme razvoja programa morate dodati neke dodatne funkcionalnosti. Može se izvršiti prije ili poslije, ili čak tijekom glavnih funkcija. Dekoratori se koriste za rješavanje ovog problema. Oni proširuju funkcionalnost, eliminirajući stvaranje drugog istog razreda s dodatnim metodama. Python dekoratori su vrsta omotača koji mijenja ponašanje funkcije. Kao promijenjeni objekt koristi se klasa, funkcija ili drugi dekorater. Trebalo bi ih vrlo pažljivo koristiti s jasnim razumijevanjem o tome što točno treba postići. Često upotreba dekoratera dovodi do komplikacije razumijevanja koda.


Dekorater i funkcija

Dekoratori u Pythonu je funkcija koja koristi drugu funkciju kao argument. To je blok koda koji vraća određenu vrijednost.
Sadrži argumente koji će se ubuduće koristiti, a utjecat će na povratnu vrijednost. Izlazni izlaz može biti bilo kojeg tipa: popis, funkcija, funkcija. U Pythonu, svaka funkcija je objekt, deklarirana je ključnom riječi def. Opseg vrijednosti nije naveden u vitičastim zagradama, nego u kartici uvlačenja. Nakon ključne riječi slijedi ime, argumentnavedene su u zagradama () iza imena. Prije prelaska na novu liniju, postavlja se simbol ":". U Pythonu, tijelo ne može biti prazno, mora sadržavati popis naredbi. Ako želite napustiti ovo mjesto, stavite praznu propusnicu operatera.

def empty_func ():

pass

Slična sintaksa proteže se na sve funkcije osim anonimne. Anonimno izgleda ovako:

func = lambda x, y: x + y

Nazovi:

func (1 2) # return 3

Izazov (druga metoda):

(lambda x, y: x + y) (1 2) # vraća 3

@ ime dekora
def modificirana funkcija
tijelo varijabilne funkcije

Shema rada opisana je sljedećim kodom:

def defator (change_funct):
def return_func1 ():
print "code before"
change_funct ()
print "code after"
povratak return_func1

Prema tome, poziv je sljedeći:

& lt; skript async = "//pagead2.googlesyndication.com/pagead/js/a dsbygoogle.js "& gt;
& lt ;! - fb_336x280_2 - & gt;

& lt; skripta & gt; (adsbygoogle = window.adsbygoogle || []). push ({});
@decorator
def retrurn_func1 ():
print new_change

Argumenti funkcije

U argumentima Python dekoratora, bilo koji tip podaci.

Varijable istog tipa prevedene su zarezima. Postoji nekoliko načina na koje su vrijednosti parametara navedene u parametrima.

  1. Normalno.
  2. Uz pomoć ključnih riječi.
  3. Zadaci statičkih vrijednosti.
  4. Uporaba pozicijskih elemenata.

Prilikom izrade, nekoliko je argumenata specificirano u određenom poretku. Kada pozivate parametre, sve su vrijednosti navedene uu ispravnom redoslijedu.

def veći (a, b):
ako je a & gt; b:
ispiši
drugo:
ispiši b

ispravan poziv:

veći 

) Pogrešan poziv:

veći 

veći (1273)

Ako su korišteni argumenti ključne riječi, njihov se poziv izvodi proizvoljno, vrijednost specificira određeni naziv-ključ.

def osoba (ime, dob):
ime ispisa, "is", "age", "years old"
osoba (dob = 23 ime = "John") 72]

Statičke vrijednosti varijabli stvaraju se zajedno s funkcijom preko operatora dodjele kao da se inicijalizacija odvijala u tijelu.


& lt; script type = "text /javascript" & gt;
može blockSettings2 = {blockId: "R-A-70350-39", renderTo: "yandex_rtb_R-A-70350-39", async:! 0};
if (document.cookie.indexOf ("abmatch =") & gt; = 0) blockSettings2.statId = 70350;
Funkcija (a, b, c, d, e) {a [c] = a [c] || [], a [c] .push (funkcija () {Ya.Context.AdvManager.render (blockSettings2)}), e = b.getElementsByTagName ("script") , d = b.createElement ("script"), d.type = "text /javascript", d.src = "//an.yandex .ru /system /context.js ", d.async =! 0e.parentNode.insertBefore (d, e)} (ovaj, ovaj.dokument," yandexContextAsyncCallbacks ");
def prostor (ime_plana, centar = "zvijezda"):
print (ime-planeta, "orbitira", centar)
prostor (Mars)
]

Kada argumenti nisu poznati u fazi stvaranja funkcije, koriste se argumenti. Mogu označiti nekoliko varijabli istog tipa ili popisa:

def func (* args):
return args
func (123 'abc')
# (123 'abc') )
func


#

Vrijednosti tipki prenose se na sličan način - koristeći znak "**".

Varijable specificirane u tijelu su lokalne, a izravno ih koristi sama funkcija. Za kreiranje globalne varijable koristi se globalni specifikator.

def get_older ():
globalna dob
dob + = 1

Podržanorekurzija.

def fact (num):
ako je num == 0:
povratak 1
drugo:
povratak num * fact (num - 1)
101]

Dekoracija metoda

Funkcije i metode su sintaktički slične.

Razlika je u tome što se funkcija naziva samo imenom.

func ()

Poziv metode provodi se kroz operatora "." i ime metode se upisuje, gdje je prvi parametar roditelj.

object.func ()

Dakle, Python dekoratori za metode su stvoreni kao i za funkciju.

Ovdje smo stvorili dekorativnu metodu branitelja method_friendly_decorator (method_to_decorate):

def wrapper (self, lie):
lie = lie - 3 #
return method_to_decorate (self, lie
povratni omotač

F ovdje je stvorio klasu s metodama koje će kasnije biti modificirane ^

klasa Lucy (objekt):
def __init __ (self) ):
self.age = 32

@method_friendly_decorator
def kažeVaše (samo, laž):
print "Ja sam% s, koliko si dao?" % (self.age + lie)

Lucy.sayYourAge (-32)
# Ja sam 26 i koliko ste dali?

Ovdje se koristi format (). Dodijeljeni za nizove formata, koji se koriste na sljedeći način:


& lt; script type = "text /javascript" & gt;
može blockSettings3 = {blockId: "R-A-70350-44", renderTo: "yandex_rtb_R-A-70350-44", async:! 0};
ako (document.cookie.indexOf ("abmatch =")) = 0) blockSettings3.statId = 70350;
Funkcija (a, b, c, d, e) {a [c] = a [c] || [], a [c] .push (funkcija () {Ya.Context.AdvManager.render (blockSettings3)}), e = b.getElementsByTagName ("script") , d = b.createElement ("script"), d.type = "text /javascript", d.src = "//an.yandex .ru /system /context.js ", d.async =! 0e.parentNode.insertBefore (d, e)} (ovaj, ovaj.dokument," yandexContextAsyncCallbacks ");
print ("string {} {}") Format (1 2)
#string 1 2

U ovom primjeru format () dvije znamenke: 1 2. Zamjenjuju znakove {} redoslijedom kojim se nalaze. Formatiranje je dostupnoisključivo za gudače. To jest, argument postaje prvo mjesto vitičastih zagrada {}, a drugi - drugi. U načinu formatiranja moguće je promijeniti redoslijed umetanja vrijednosti. To se radi preko indeksa.

Ako:

print ("string {} {}") Format (1 2)
#string 1 2

: R3r3r3701.

print ("string {1} {0}".) Format (1 2)
#string 2 1

Dopušteno je formatirati linije kroz imena ključeva u formatu (arg1 = vrijednost1 arg2 = vrijednost2).

print ("string {arg1} {arg2}") Format (arg1 = 1 arg2 = 2)
#string 1 2

sustav - kada u dva argumenta samo jedna od njih ima statičku vrijednost. Za prijenos vrijednosti označava se indeks i naziv varijable.

& lt; skripta async = "//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js">

& lt; skripta & gt; (adsbygoogle = window.adsbygoogle || []). push ({});
print ("string {arg1} {1}".) Format (arg1 = 1 2)
#string 1 2

Dekorateri s argumentima

]

Argumente možete poslati Python dekoraterima, koji naknadno modificiraju obrađenu funkciju.

def decator (function_to_decorate):
def funkcija (arg1 arg2):
print "Vidi što sam dobio:", arg1 arg2
povratna funkcija
]

U tom slučaju postoji @decorator koji modificira funkciju. Argumenti su preskočeni na drugom retku, a prenosi ih varijabla function_to_decorate.

@decorator
def real_func (Peter Ivanovič)
print "Moje ime", arg1 arg2

Na zaslonu će se pojaviti:

Vidi što sam dobio: Peter Ivanovich 

Moje ime je Peter Ivanovich

Ugrađeni dekoratori

Dovoljno je jednog dekoratera, realizirano je nekoliko razina obloga. Kada stvarateSvaki ugrađeni dekorator započinje s novom linijom, broj redaka određuje razinu težine. Izgleda ovako:

@AAA
@BBB
@CCC
def funkcija ():
pass:

U skladu s tim, AAA ), prihvaća BBB () parametre i obrađuje CCC ().

def f ():
pass:

f = (AAA BBB (CCC (funkcija))):

Funkcija se prenosi s tri različitim dekoraterima, dodjeljuje se f (). Svaki od njih vraća svoj rezultat, koji pak zauzima omot. Možete primijetiti da je posljednji dekorater popisa prvi, on počinje funkciju obrade ().

U Pythonu izgledaju i klasni dekoratori.

prolaz:

C = prvi dekorator (drugi dekorator (CDC))
)

XX = C ()

def fn1 (arg): povratna lambda: 'XX' + arg ()

def fn2 (arg): return lambda: ' YY '+ arg ()

def fn3 (arg): povratna lambda:' ZZ '+ arg ()

@ fn1

@ fn2

@ fn3

def myfunc (): # myfunc = fn1 (fn2 (fn3 (myfunc)))

povratak 'Python'

print (myfunc ()) # "XXYYZZPython"

U ovom slučaju, implementacija logike prelamanja događa se pomoću def lambda:


& lt; script type = "text /javascript" & gt;
može blockSettings = {blockId: "R-A-70350-45", renderTo: "yandex_rtb_R-A-70350-45", async: 0};
if (document.cookie.indexOf ("abmatch =")> = 0) blockSettings.statId = 70350;
Funkcija (a, b, c, d, e) {a [c] = a [c] || [], a [c] .push (funkcija () {Ya.Context.AdvManager.render (blockSettings}), e = b.getElementsByTagName ("script") , d = b.createElement ("script"), d.type = "text /javascript", d.src = "//an.yandex .ru /system /context.js ", d.async =! 0e.parentNode.insertBefore (d, e)} (ovaj, ovaj.dokument," yandexContextAsyncCallbacks ");
Lambda: 'XX' + arg ()

Fn3 () rotira myfunc, vraća ZZPython umjesto prethodnog retka Pythona. Tada reverzibilni fn2 () počinje raditi, što na kraju vraća rezultat YYZZPython. Na kraju fn1 () obrađuje myfunc () iVraća krajnji rezultat - liniju XXYYZZPython.

Ugrađeni dekoratori

Postoje ugrađeni dekoratori Python funkcija. Oni dolaze zajedno s tumačem, da biste ih mogli koristiti za uvoz dodatnih modula.

Staticmethod upravlja funkcijom argumenta tako da ona postaje statična i prihvaća statički specifikator.

klasa C: 

@staticmethod

def f (arg1 arg2): #static

pass

) Classmethod čini klasu s obrađenom funkcijom.

class MyClass: 

@classmethod

def metoda (cls, arg):

print ('% s classmethod.
cls.method



def call_class_method (
self: method

self.method

klasa (MyClass):

@classmethod

def call_original_method (cls):

cls.method



Klasa metode MyClass.method

# MyClass. 0

MyClass.call_original_method () # klasa klase MyClass. 5

MySubclass.method

# klasa klase MySubclass. 0

MySubclass.call_original_method () #Klasa metode MySubclass. 6

# Klasne metode nazivamo kroz objekt.

my_obj = MyClass ()

my_obj.method



my_obj.call_class_method ()

dekoraciju.

Zamjena taložnika i rastvarača

Uz pomoć razreda imovine imenovanih bajtovi, postavljači, delleteri.

svojstvo klase ([fget [, fset [, fdel [, doc]]]])]

Tipografske noge i postavke su sljedeće:

Prijenos parametara na Python klasu se provodi. Uređaj za dekoraciju nekretnina ima metode:

  • fget - dobiva vrijednost atributa;
  • fset definira vrijednost atributa;
  • fdel uklanja;
  • doc stvara opis atributa. Ako dokument nijeje dodijeljena, vraća kopiju opisa fget (), ako postoji.

klasa C (objekt):

Def __init __ (self):

self._x = ništa

def getx (self):


def-setx (samo) vrijednost:

self._x = vrijednost

def delx (self):

za self._x

x = svojstvo (getx, setx, delx, "Ja sam svojstvo" x ".))

Korištenje Pythonovih svojstava kao dekoratera:


klasa C (objekt): 

def __init __ (self):

self._x = None

@property

def x (self):

"" "Ja sam 'x' svojstvo." ""

povratak self._x

@ x.setter

349) def x (self, value):

self._x = vrijednost

@ x.deleter

def x (self):

self._x

Svojstvo je stvorilo funkcije x dekorater. Budući da svi dekoratori imaju ugrađeni setter, getter, deletter metode, možete pozvati jednu od njih.

Značajke

Prilikom rada s dekoratorom morate uzeti u obzir neke značajke:

  1. Korištenje dekoratera malo usporava poziv funkcije.
  2. Nakon što se oštećena funkcija ne može razdijeliti. Postoje načini zaobići ovo pravilo. Možete stvoriti dekorater koji kasnije možete odvojiti od funkcije. Ali to nije dobra praksa.
  3. Zbog činjenice da dekorater okreće funkciju, otklanjanje pogrešaka može biti komplicirano. Problem se rješava pomoću modula functools.

Functools modul je skup metoda koje omogućuju interakciju s drugim funkcijama, a također je i Python dekorater.

Korisna metoda cmp_to_key (func) pretvara cmp () ključ (). Obje metode služe za sortiranje popisa, ali prva je uklonjena iz Pythona 3.0, a druga je dodana u verziji 2. Lru_cache pohranjuje posljednjepoziva u predmemoriju. Ako je maxsixe naveden kao none, veličina predmemorije se povećava neograničeno. Rječnik se koristi za spremanje često korištenih upita. Ako je argument typed = true, argumenti različitih tipova su zasebno predmemorirani. Prema tome, kada se upisuje = true, pohranjuju se u jedan popis.

Total_ordering ukrašava klasu koja sadrži metode usporedbe i dodaje sve ostale.

Djelomične (func, * args, ** keywords) vraćaju funkciju koju je pozvao prvi argument iz opsega parametara metode, prosljeđuje pozicijske * argumente, koje je dao drugi, i nazvane kwargs.

Redukcija radi ovako:

smanjuje (lambda x, y: x + y, [1, 2, 3, 4, 5])

) Ekvivalent:

((((+1 +2) +3) +4) +5)

Smanjenje koristi zadanu funkciju u nizu parova elemenata navedenih u * * ključne riječi ili sve stavke * args. Dakle, u gornjem primjeru, koristeći lambda funkciju, obrađena su prva dva elementa:

1 + 2

Sljedeći rezultat se zbraja s trećim, rezultat dobiven iz tog rezultata dodaje se sljedećem:

Update_wrapper ažurira ljusku tako da podsjeća na omotanu funkciju. Argumenti određuju ove dvije funkcije, kopirane i ažurirane atribute.

dodijeljena = WRAPPER_ASSIGNMENTS

Kolica WRAPPER_ASSIGNMENTS sadrži zadane vrijednosti za __name__, __module__, __annotations__ i __doc__.

ažurirano = WRAPPER_UPDATES

WRAPPER_UPDATES označava ažurirane atribute, po defaultu je __dict__.

Oblozi nazivaju djelomični dekorater.

Uređaj za uklanjanje pogrešaka

Mogućnosti dekoratera omogućuju vam da ih stvoritefunkcija koja, u slučaju pogreške, proizvede jedan rezultat, ako nema grešaka, u drugi.

Implementacija:

import functools def retry (func): @ functools.wraps (func) def wrapper (* args, ** kwargs): dok je True: pokušaj : return func (* args, ** kwargs) osim Exception: pass return wrapper

Vidljivo je da se u slučaju iznimaka funkcija ponovno pokreće.

@retry def do_something_unreliable (): ako je random.randint (010) & gt; 1: podignite IOError ("Slomljeno umak, sve je obloženo!") Drugo: vratite "Strašan umak!" print (do_something_unreliable ())

Ovaj kod znači da će 9 od 11 slučajeva naići na pogrešku.

def my_decorator (fn): def wrapped (): pokušaj: vrati fn () osim kao iznimka e: print ("Error:", e) vrati wrapped @ my_decorator def my_func (): import random (while) True: ako je random.randint (0 4) == 0: podignite Exception ('Random!') print ('Ok') my_func ()

Ovdje u konzoli možete vidjeti:

U redu Ok Ok Ok: Random!

Stvaranje vašeg dekoratera

Dekorater je funkcija unutar koje postoji druga funkcija s odgovarajućim metodama.

Primjer dekoratera u Pythonu:

def my_shiny_new_decorator (function_to_decorate): 

def the_wrapper_around_the_original_function ():

print - kôd koji se pokreće do poziva funkcije ")

print (" Ja sam kôd koji radi nakon ")


vraća the_wrapper_around_the_original_function

U ovom kodu dekorater je my_shiny_new_decorator (). Kasnije dekorira function_to_decorate () iz područja parametara. the_wrapper_around_the_original_function primjer je kako će se obrađena funkcija obraditi. U ovom slučaju, dodaje se sljedeće:

print 

print ("Ja sam kôd koji radi poslije")

My_shiny_new_decorator () vraća the_wrapper_around_the_original_function () na dekoraciju.

ToKako bi riješili bilo koju funkciju, okreće se dekorater.

stand_alone_function = my_shiny_new_decorator (stand_alone_function)

U ovom slučaju, funkcija je set-stand_alone_function, dekorater je my_shiny_new_decorator. Vrijednost je dodijeljena varijabli stand_alone_function.

def stand_alone_function (): 

print ("Ja sam jednostavna usamljena funkcija, ne smijete me mijenjati?")

stand_alone_function ()
435]
Ja sam kod koji funkcionira prije pozivanja funkcije 

Ja sam jednostavna usamljena funkcija, jer me nećete usuditi promijeniti?

I ja sam kod koji radi nakon


Dakle, očito je da stand_alone_function, koja prikazuje jednu rečenicu, sada prikazuje tri rečenice. To se radi pomoću dekoratera.

Povezane publikacije