2015-05-18 12 views
6

Ho sempre pensato che le funzioni di Python 2.7 si riferissero all'ambito in cui erano definite. Considera il seguente codice. Perché la seconda uscita non è "calcolando: sin"?Informazioni sulle chiusure Python

C'è un modo per modificare il codice in modo che funzioni come previsto?

import math 

mymath = dict() 

for fun in ["sin", "cos"]: 
    def _impl(val): 
     print "calculating: %s" % fun 
     return getattr(math, fun)(val) 
    mymath[fun] = _impl 

# calculating: cos 
print mymath["cos"](math.pi) 

# calculating: cos <- why? 
print mymath["sin"](math.pi) 

risposta

7

Il valore di fun viene valutata quando viene chiamata la funzione.

Nell'esempio fornito, fun è una variabile globale e il suo valore è "cos" dopo il ciclo for.

Penso che si supponga che il valore di fun venga sostituito quando si crea la funzione, ma non lo è. La funzione valuta il valore della variabile quando viene eseguita esattamente come dovrebbe.

Non si tratta dello spazio dei nomi in cui viene definita la funzione, ma lo spazio dei nomi in cui si esegue la funzione.

import math 

mymath = dict() 

for fun in ["sin", "cos"]: 
    def _impl(val): 
     print "calculating: %s" % fun 
     return getattr(math, fun)(val) 
    mymath[fun] = _impl 


fun = 'tan' 
# will print and calculate tan 
print mymath["cos"](math.pi) 
2

Da questo codice (che funziona come desiderato)

my = {} 

def makefun(fun): 
    def _impl(x): 
    print fun, x 
    return _impl 

for fun in ["cos", "sin"]: 
    my[fun] = makefun(fun) 

# will print 'cos' 
my['cos'](1) 
fun = 'tan' 
# will print 'cos' 
my['cos'](2) 

sembra che non è lo spazio dei nomi della definizione di funzione che decide in merito alla natura della chiusura, ma invece lo spazio dei nomi del variabili usate Più test:

my = dict() 

fun = '' 

def makefun(): 
    global fun #This line is switched on or off 
    fun = 'sin' 
    def _impl(x): 
    print fun, x 
    return _impl 

test = makefun() 

#gives sin 1 
test(1) 
fun = 'cos' 
#gives sin 2 if line global fun is used 
#gives cos 2 if line global fun is NOT used 
test(2) 

Quindi la spiegazione corretta sembra essere che la chiusura salva un riferimento ai suoi argomenti e non un valore.

0

penso che si sta tentando di fare le cose più difficili: Ecco come si può fare con le chiusure:

import math 

mymath = dict() 


def funcmaker(fun): 
    print "creating %s function" % fun 
    def calculate(val): 
     print "calculating: %s" % fun 
     return getattr(math, fun)(val) 
    return calculate 

print funcmaker("sin")(math.pi) 
print funcmaker("cos")(math.pi) 

Sopra codice che dà il seguente risultato:

creating sin function 
calculating: sin 
1.22464679915e-16 
creating cos function 
calculating: cos 
-1.0 
Problemi correlati