Python Closures: come usarlo e perché?

In questo tutorial imparerai a conoscere la chiusura di Python, come definire una chiusura e i motivi per cui dovresti usarla.

Variabile non locale in una funzione nidificata

Prima di entrare in cosa sia una chiusura, dobbiamo prima capire cos'è una funzione annidata e una variabile non locale.

Una funzione definita all'interno di un'altra funzione è chiamata funzione annidata. Le funzioni annidate possono accedere alle variabili dell'ambito che le racchiude.

In Python, queste variabili non locali sono di sola lettura per impostazione predefinita e dobbiamo dichiararle esplicitamente come non locali (utilizzando la parola chiave non locale) per modificarle.

Di seguito è riportato un esempio di una funzione nidificata che accede a una variabile non locale.

 def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) printer() # We execute the function # Output: Hello print_msg("Hello")

Produzione

 Ciao

Possiamo vedere che la printer()funzione annidata è stata in grado di accedere alla variabile msg non locale della funzione che lo racchiude.

Definizione di una funzione di chiusura

Nell'esempio sopra, cosa accadrebbe se l'ultima riga della funzione print_msg()restituisse la printer()funzione invece di chiamarla? Ciò significa che la funzione è stata definita come segue:

 def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) return printer # returns the nested function # Now let's try calling this function. # Output: Hello another = print_msg("Hello") another()

Produzione

 Ciao

È insolito.

La print_msg()funzione è stata chiamata con la stringa "Hello"e la funzione restituita è stata associata al nome un altro. Alla chiamata another(), il messaggio veniva comunque memorizzato anche se avevamo già terminato l'esecuzione della print_msg()funzione.

Questa tecnica con la quale alcuni dati ( "Helloin questo caso) vengono allegati al codice è chiamata chiusura in Python .

Questo valore nell'ambito di inclusione viene ricordato anche quando la variabile esce dall'ambito o la funzione stessa viene rimossa dallo spazio dei nomi corrente.

Prova a eseguire quanto segue nella shell Python per vedere l'output.

 >>> del print_msg >>> another() Hello >>> print_msg("Hello") Traceback (most recent call last):… NameError: name 'print_msg' is not defined

Qui, la funzione restituita funziona ancora anche quando la funzione originale è stata eliminata.

Quando ci sono le chiusure?

Come si vede dall'esempio sopra, abbiamo una chiusura in Python quando una funzione annidata fa riferimento a un valore nel suo ambito di inclusione.

I criteri che devono essere soddisfatti per creare la chiusura in Python sono riassunti nei seguenti punti.

  • Dobbiamo avere una funzione annidata (funzione all'interno di una funzione).
  • La funzione annidata deve fare riferimento a un valore definito nella funzione che lo racchiude.
  • La funzione che lo racchiude deve restituire la funzione nidificata.

Quando utilizzare le chiusure?

Allora a cosa servono le chiusure?

Le chiusure possono evitare l'uso di valori globali e forniscono una qualche forma di occultamento dei dati. Può anche fornire una soluzione orientata agli oggetti del problema.

Quando ci sono pochi metodi (un metodo nella maggior parte dei casi) da implementare in una classe, le chiusure possono fornire una soluzione alternativa e più elegante. Ma quando il numero di attributi e metodi aumenta, è meglio implementare una classe.

Ecco un semplice esempio in cui una chiusura potrebbe essere più preferibile rispetto alla definizione di una classe e alla creazione di oggetti. Ma la preferenza è tutta tua.

 def make_multiplier_of(n): def multiplier(x): return x * n return multiplier # Multiplier of 3 times3 = make_multiplier_of(3) # Multiplier of 5 times5 = make_multiplier_of(5) # Output: 27 print(times3(9)) # Output: 15 print(times5(3)) # Output: 30 print(times5(times3(2)))

Produzione

 27 15 30

Anche i Python Decorators fanno un ampio uso di chiusure.

In una nota conclusiva, è bene sottolineare che i valori che vengono racchiusi nella funzione di chiusura possono essere individuati.

Tutti gli oggetti funzione hanno un __closure__attributo che restituisce una tupla di oggetti cella se si tratta di una funzione di chiusura. Facendo riferimento all'esempio sopra, conosciamo times3e times5sono funzioni di chiusura.

 >>> make_multiplier_of.__closure__ >>> times3.__closure__ (,)

L'oggetto cella ha l'attributo cell_contents che memorizza il valore chiuso.

 >>> times3.__closure__(0).cell_contents 3 >>> times5.__closure__(0).cell_contents 5

Articoli interessanti...