English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Tutorial di base di Python

Controllo dei flussi in Python

Funzione in Python

Tipi di dati di Python

Operazioni di file in Python

Oggetti e classi in Python

Date e ora in Python

Conoscenze avanzate di Python

Manuale di Python

Decoratore in Python

I decoratori accettano una funzione, aggiungono alcune funzionalità e la restituiscono. In questo articolo, imparerai come creare decoratori e perché è utile usarli.

Cos'è un decoratore in Python?

Python ha una funzione interessante chiamataDecoratoriper aggiungere funzionalità al codice esistente.

questo viene anche chiamatoMeta-programmazione,Perché una parte del programma tenta di modificare un'altra parte del programma durante la compilazione.

Prerequisiti per imparare i decoratori

Per comprendere i decoratori, dobbiamo prima comprendere alcune conoscenze di base di Python.

Dobbiamo accettare il fatto che tutto in Python èOggetto. I nomi che definiamo sono solo identificatori associati a questi oggetti.FunzioneAnche loro non sono esenti, sono oggetti (con attributi). Puoi associare nomi diversi allo stesso oggetto funzionale.

Questo è un esempio.

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

Quando esegui il codice, le due funzioni first e second producono lo stesso output. In questo caso, i nomi first e second si riferiscono allo stesso oggetto funzionale.

Ora, la situazione sembra un po' più complessa, puoi passare una funzione come parametro a un'altra funzione.

Se hai già utilizzato funzioni come map, filter e reduce in Python, allora sai già questo.

Questo tipo di funzione che accetta altre funzioni come parametri è anche chiamatoAlta funzione. Questo è un esempio di tale funzione.

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

Chiamiamo la funzione nel modo seguente.

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

Inoltre, una funzione può restituire un'altra funzione.

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

In questo caso, is_returned() è una funzione annidata, che viene definita e restituita ogni volta che chiamiamo is_drawn().

Infine, dobbiamo capireClosure in Python.

Torniamo ai decoratori

Le funzioni e i metodi sono chiamatiInvocabile,Poiché possono essere chiamati.

In realtà, qualsiasi oggetto che implementi il metodo speciale __call__() è chiamato invocabile. Pertanto, nel senso più basilare, i decoratori sono invocabili e possono restituire oggetti invocabili.

In sostanza, i decoratori accettano una funzione, aggiungono alcune funzionalità e la restituiscono.

def make_pretty(func):
    def inner():
        print("Sono stato decorato")
        func()
    return inner
def ordinary():
    print("Sono una funzione comune")

Quando si esegue il seguente codice in shell,

>>> ordinary()
Sono una funzione comune
>>> # Decoriamo questa funzione comune
>>> pretty = make_pretty(ordinary)
>>> pretty()
Sono stata decorata
Sono una funzione comune

Nel esempio mostrato, make_pretty() è un decoratore. Nel passo di assegnazione.

pretty = make_pretty(ordinary)

La funzione ordinary() è stata decorata, e la funzione restituita è chiamata pretty.

Possiamo vedere che il decoratore aggiunge alcune nuove funzionalità alla funzione originale. È come avvolgere un regalo. Il decoratore agisce come involucro. La natura dell'oggetto avvolto (il regalo dentro) non cambia. Ma ora sembra più bello (dopo l'avvolgimento).

Di solito, decoriamo una funzione e la riassegniamo come

ordinary = make_pretty(ordinary).

Questa è una costruzione comune, quindi Python ha una sintassi semplificata per questo.

Possiamo usare il simbolo @ insieme al nome del decoratore e metterlo sopra la definizione della funzione da decorare. Ad esempio:

@make_pretty
def ordinary():
    print("Sono una funzione comune")

è equivalente a

def ordinary():
    print("Sono una funzione comune")
ordinary = make_pretty(ordinary)

Questo è solo uno zucchero sintattico per implementare il decoratore.

Decorare una funzione con parametri

Il decoratore sopra è semplice e si applica solo a funzioni senza parametri. Cosa succede se la nostra funzione ha come parametri quelli mostrati di seguito?

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

Questa funzione ha due parametri:aeb. Sappiamo che se mettiamobSe viene passato 0, si genererà un errore.

>>> divide(2,5)
0.4
>>> divide(2,0)
Traceback (chiamata più recente per ultima):
...
ZeroDivisionError: divisione per zero

Ora facciamo un decoratore per verificare se questa situazione causerebbe un errore.

def smart_divide(func):
   def inner(a,b):
      print("Devo fare la divisione", a, "e", b)
      if b == 0:
         print("Ohimè! Non posso dividere")
         return
      return func(a,b)
   return inner
@smart_divide
def divide(a,b):
    return a/b

Se si verifica un errore, questa nuova implementazione restituirà None.

>>> divide(2,5)
Devo fare la divisione 2 e 5
0.4
>>> divide(2,0)
Devo fare la divisione 2 e 0
Oh no! Non posso dividere

In questo modo, possiamo decorare funzioni con parametri.

Un osservatore attento noterà che i parametri della funzione annidata all'interno del decoratore inner() sono gli stessi della funzione decorata. Considerando questo, possiamo ora rendere i decoratori universali capaci di utilizzare un numero arbitrario di parametri.

In Python, questo magia è completato tramite il function(*args, **kwargs). Così, args sono i parametri posizionali.TupleInvece di kwargs, sono i parametri chiave.Dizionario. Un esempio di decoratore di questo tipo è.

def works_for_all(func):
    def inner(*args, **kwargs):
        print("Posso decorare qualsiasi funzione")
        return func(*args, **kwargs)
    return inner

Decoratori collegati in Python

È possibile collegare più decoratori in Python.

Questo significa che una funzione può essere decorata più volte (o la stessa) con decoratori diversi. Dobbiamo solo posizionare i decoratori sopra la funzione desiderata.

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

Questo produrrà l'output.

******************************
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Ciao
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
******************************

la sintassi sopra,

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

è equivalente a

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

L'ordine dei decoratori è importante. Se li mettiamo in ordine opposto,

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

L'esecuzione avverrà

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
******************************
Ciao
******************************
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%