2013-01-19 12 views

risposta

29

Le celle di chiusura si riferiscono ai valori necessari per la funzione ma vengono ricavate dall'ambito circostante.

Quando Python compila una funzione nidificata, annota tutte le variabili a cui fa riferimento ma sono definite solo in una funzione padre (non globale) negli oggetti codice per la funzione nidificata e l'ambito genitore. Questi sono gli attributi co_freevars e co_cellvars sugli oggetti __code__ di queste funzioni, rispettivamente.

Quindi, quando in realtà creare la funzione nidificata (che si verifica quando viene eseguita la funzione padre), tali riferimenti vengono quindi utilizzati per collegare una chiusura alla funzione nidificata.

Una chiusura di funzione contiene una tupla di celle, una per ciascuna variabile libera (denominata in co_freevars); le celle sono riferimenti speciali alle variabili locali di un ambito genitore, che seguono i valori a cui puntano le variabili locali. Questo è meglio illustrato con un esempio:

def foo(): 
    def bar(): 
     print(spam) 

    spam = 'ham' 
    bar() 
    spam = 'eggs' 
    bar() 
    return bar 

b = foo() 
b() 

Nell'esempio precedente, la funzione bar ha una cella di chiusura, che indica spam nella funzione foo. La cella segue il valore di spam. Ancora più importante, una volta che foo() viene completato e viene restituito bar, la cella continua a fare riferimento al valore (la stringa eggs) anche se la variabile all'interno di foo non esiste più.

Pertanto, le uscite di codice di cui sopra:

>>> b=foo() 
ham 
eggs 
>>> b() 
eggs 

e b.__closure__[0].cell_contents è 'eggs'.

Si noti che la chiusura è dereferenziata quando bar() viene chiamato; la chiusura non cattura il valore qui. Che fa la differenza quando si produce funzioni annidate (con lambda espressioni o def dichiarazioni) che fanno riferimento l'indice del ciclo:

def foo(): 
    bar = [] 
    for spam in ('ham', 'eggs', 'salad'): 
     bar.append(lambda: spam) 
    return bar 

for bar in foo(): 
    print bar() 

È possibile che questo stamperà salad tre volte di fila, perché tutti e tre lambda funzioni riferimento alla variabile spam , non il valore a cui è stato associato quando è stato creato l'oggetto funzione. Al termine del ciclo for, spam è stato associato a 'salad', quindi tutte e tre le chiusure verranno risolte in tale valore.

4

È il nuovo nome di Python 3 per il vecchio func_closure.

http://docs.python.org/3.0/whatsnew/3.0.html

Gli attributi di funzionalità di nome func_X sono stati rinominati per utilizzare il modulo __X__, liberando questi nomi l'attributo funzione di spazio dei nomi per gli attributi definiti dall'utente. Vale a dire, func_closure, func_code, func_defaults, func_dict, func_doc, func_globals, func_name sono stati rinominati a __closure__, __code__, __defaults__, __dict__, __doc__, __globals__, __name__, rispettivamente.

In sintesi:

__closure__ è None o un tuple di cellule che contengono vincolanti per le variabili libere della funzione.

Inoltre, NON è scrivibile.

Riferimento: http://docs.python.org/ref/types.html

Esempio Python < 3 (così sto usando func_closure)

def foo(): 
    x = "I am used" 
    y = "I am free" 
    z = "I am free too" 

    def bar(x): 
     return x, y, z 

    return bar 

c = foo().func_closure 

print [i.cell_contents for i in c] 

uscita:

>>> 
['I am free', 'I am free too'] 

Come foo sta tornando la funzione bar che sta usando il proprio valore x, ma non o z. Quindi, sono inferiori a __closure__.

1
>>> def f(): 
...  a = "HELO" 
...  b = 1.0 
...  def w(c): 
...   return a,b,c 
...  return w 

>>> w = f() 
>>> w.__closure__ 
(<cell at 0xa05c4ac: str object at 0x9e91b74>, <cell at 0xa05c3bc: float object at 0xb733dde8>) 
>>> w.__closure__[0].cell_contents 
'HELO' 
>>> w.__closure__[1].cell_contents 
1.0 

non ho mai visto il tipocellulare utilizzato in qualsiasi altro luogo. Sembra essere costruito appositamente per contenere le variabili di chiusura.