2010-08-19 19 views
6

Dado el siguiente código:variable de Python resolver

a = 0 
def foo(): 
    # global a 
    a += 1 
foo() 

Cuando se ejecuta, se queja de Python: UnboundLocalError: variable local 'a' hace referencia antes de la asignación

Sin embargo, cuando se trata de un diccionario ...

a = {} 
def foo(): 
    a['bar'] = 0 
foo() 

La cosa funciona muy bien ...

Alguien sabe por qué podemos hacer referencia a a en el 2 ° trozo de código, ¿pero no en el 1er?

Respuesta

2

La diferencia es que en el primer ejemplo está asignando a a que crea un nuevo nombre local a que esconde el mundial a.

En el segundo ejemplo no está haciendo una asignación a a por lo que se utiliza el a global.

Esto se cubre en el documentation.

A special quirk of Python is that – if no global statement is in effect – assignments to names always go into the innermost scope.

+0

Me pregunto por qué decidieron describirlo como un "capricho especial". Contraste con javascript donde 'a = 1' se asigna automáticamente al alcance global. Lo único bueno de eso es que puedes reconocer rápidamente el código basura por las ausencias de 'var a = 1' – aaronasterling

1

La pregunta es sobre la actualización. No se puede actualizar a porque no es una variable en el espacio de nombres local de su función. La operación de asignación de actualización in situ no actualiza a en su lugar.

Curiosamente, a = a + 1 también falla.

Python genera un código ligeramente optimizado para este tipo de declaraciones. Utiliza una instrucción "LOAD_FAST".

2   0 LOAD_FAST    0 (a) 
       3 LOAD_CONST    1 (1) 
       6 INPLACE_ADD   
       7 STORE_FAST    0 (a) 
      10 LOAD_CONST    0 (None) 
      13 RETURN_VALUE   

Tenga en cuenta que el uso de a en el lado izquierdo y derecho del signo igual conduce a esta optimización.

Puede, sin embargo, acceder al a porque Python buscará espacios de nombres locales y globales por usted.

Dado que a no aparece en el lado izquierdo de una instrucción de asignación, se utiliza un tipo diferente de acceso, "LOAD_GLOBAL".

2   0 LOAD_CONST    1 (0) 
       3 LOAD_GLOBAL    0 (a) 
       6 LOAD_CONST    2 ('bar') 
       9 STORE_SUBSCR   
      10 LOAD_CONST    0 (None) 
      13 RETURN_VALUE   
0

a += 1 es equivalente a a = a + 1. Asignando a la variable a, se hace local. El valor que intenta asignar a + 1 falla porque a no ha sido enlazado todavía.

0

Esa es una muy Gotcha Python común: si asigna a una variable dentro de una función (como lo hace, con +=), en cualquier lugar en absoluto (no necesariamente antes de usarlo de otra manera), no lo hace usa el global. Sin embargo, como lo que estás haciendo es efectivamente "a = a + 1", estás intentando acceder al a (en el lado derecho de la expresión) antes de asignarlo.

Pruebe usar global a al principio de su función (pero tenga en cuenta que sobrescribirá el valor global a).

En su segundo ejemplo, no está asignando la variable a, sino solo a uno de sus elementos. Entonces se usa el dict global a.

Cuestiones relacionadas