2010-08-07 9 views
39

Estoy tratando de crear funciones dentro de un bucle y almacenarlas en un diccionario. El problema es que todas las entradas en el diccionario parecen terminar mapeando a la última función creada. El código es el siguiente:Crear funciones en un bucle

d = {} 
def test(**kwargs): 
    for k in kwargs: 
     def f(): 
      print k, kwargs[k] 
     d[k] = f 
     f() 

test(foo=1, bar=2) 
print 'should print the same output as before' 
d['foo']() 
d['bar']() 

Este salidas:

foo 1 
bar 2 
should print the same output as before 
bar 2 
bar 2 

Cualquier idea de por qué?

+1

como un recordatorio para mí: http://docs.python-guide.org/en/latest/writing/gotchas/#late-binding-closures –

Respuesta

82

que se está ejecutando en un problema con el enlace en tiempo - cada función k mira hacia arriba lo más tarde posible (por lo tanto, cuando se le llama fuera test, esto sucede después de que el final del bucle).

fija fácilmente al forzar el enlace anticipado: el cambio def f(): a def f(k=k): - los valores por defecto (el de la derecha k en k=k es un valor por defecto para el nombre de argumento k, el cual es el de la izquierda en kk=k) son la mirada hacia def vez, no en call vez, por lo que, esencialmente, son una forma de buscar específicamente una vinculación anticipada.

Si usted está preocupado acerca f conseguir un argumento extra (y por lo tanto potencialmente ser llamado erróneamente), hay una manera más sofisticada, que implicó el uso de un cierre como una "fábrica de función":

def make_f(kwargs, k): 
    def f(): 
     print k, kwargs[k] 
    return f 

y en su ciclo usa f = make_f(kwargs, k) en lugar de la declaración def.

Cuestiones relacionadas