Dekoratori

17.8 Dekoratori

Dekorator možeš da zamisliš kao prečicu za primenu tzv wrapper funkcije. Wrapper funkcije su takve funkcije koje pozivaju neku drugu funkciju, a da pri tome one mogu da rade nešto svoje ili da ne rade ništa (tj, mogu da pripremaju „sirove“ podatke iz programa za format koji glavna funkcija očekuje i slično). U suštini dekoratori nam mogu biti korisni da  bi smo "wrap" funkciju pozivali konstantno - sa istim delom programa, iznova i iznova dokle god se ne obavi potrebna obrada. Na primer, kreirao sam dekorator koji se zove ponovo, kako bih ga mogao primeniti na bilo kojoj funkciji, koji mi služi da, ukoliko se pojavi neka greška u radu, Python ne prekine izvršavanje programa, već da pokuša ponovno da pokrene funkciju, i to najviše 5 puta, sa malom pauzom između svakog novog pokušaja da obavi zadatak. Ovo može biti korisno u nekim situacijama, kao što su pokušaji uspostavljanja komunikacije sa računarom koji je negde na mreži (intrnetu):
#!/usr/bin/env python3 

'''Skripta koja simulira pokušaj uspostavljanja komunikacije.''' 

from time import sleep 
from functools import wraps 
import logging 

logging.basicConfig() 
log = logging.getLogger("ponovo") 

def ponovo(f): 
    @wraps(f) 
    def wrapped_funkcija(*arg, **kvarg): 
        MAKS_POKUSAJ = 5 
        for pokusaj in range(1, MAKS_POKUSAJ + 1): 
            try: 
                return f(*arg, **kvarg) 
            except: 
                log.exception("Pokušaj %s/%s nije uspeo : %s", 
                pokusaj, 
                MAKS_POKUSAJ, 
                (arg, kvarg)) 
                sleep(10 * pokusaj) 
            log.critical("Svi %s pokušaji su propali : %s", 
            MAKS_POKUSAJ, 
            (arg, kvarg)) 
    return wrapped_funkcija 

brojac = 0 

@ponovo 
def sacuvaj_u_bazu(arg): 
    print("Piši u bazu podataka ili uspostavi netvork konekciju itd.") 
    print("Ovo će se automatski ponovo izvršavati, ukoliko dođe do neke greške.") 
    global brojac 
    brojac += 1 
    if brojac < 2: 
        raise ValueError(arg) 
    
if __name__ == '__main__': 
    sacuvaj_u_bazu("Neka loša vrednost")
Što nam daje sledeći izlaz:
./pokusaj.py 
Piši u bazu podataka ili uspostavi netvork konekciju itd. 
Ovo će se automatski ponovo izvršavati, ukoliko dođe do neke greške. 
ERROR:ponovo:Pokušaj 1/5 nije uspeo : (('Neka loša vrednost',), {}) 
Traceback (most recent call last): 
  File "./pokusaj.py", line 18, in wrapped_funkcija 
    return f(*arg, **kvarg) 
  File "./pokusaj.py", line 39, in sacuvaj_u_bazu 
    raise ValueError(arg) 
ValueError: Neka loša vrednost 
CRITICAL:ponovo:Svi 5 pokušaji su propali : (('Neka loša vrednost',), {}) 
Piši u bazu podataka ili uspostavi netvork konekciju itd. 
Ovo će se automatski ponovo izvršavati, ukoliko dođe do neke greške. 
Ovo je malo napredan primer, ne moraš da ga znaš, ali je bitno da ga razumeš. Kao što vidiš, glavna funkcija nam je sacuvaj_u_bazu(). Budući da sam ispred nje koristio dekorator koji poziva funkciju ponovo() ovaj program pokušava da 5 puta izvrši glavnu funkciju. Obrati pažnju da je dekorator celu glavnu funkciju prosledio kao argument funkciji ponovo(), tj dekorator je uradio ovu stvar: ponovo(sacuvaj_u_bazu()). Za više informacija kako se radi sa dekoratorima pročitaj sadržaj koji se nalazi na ovom mestu.

17.7 assert naredba Indeks 17.9 Razlike između
verzija

Primjedbe

Popularno

Kako televizija štetno utiče na Vaše zdravlje finansije?

Da li je TV kviz Slagalica "prevara"?

Tu je novi Qt creator 4.4.0!

Kada prijatelji odlaze

Microsoft objavio - nova verzija Windowsa stiže...

Opet su se pojavili lažni kuponi brenda "IDEA" na društvenim mrežama

Najgore obrade velikih rock hitova

Sitnije promene na blogu...

Poslednji pozdrav izgubljenom vremenu

Ne, Marlboro ne deli besplatne cigarete!