2010-08-19 6 views
6

Vu le code suivant:variables Python résolution

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

Effectué, Python se plaint: UnboundLocalError: variable locale 'a' fait référence avant l'affectation

Cependant, quand il est un dictionnaire ...

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

La chose exécute très bien ...

Quelqu'un sait pourquoi nous pouvons référencer un dans le 2ème morceau de code, mais pas le 1er?

Répondre

2

La différence est que dans le premier exemple, vous assignez à a qui crée un nouveau nom local a qui cache la a mondiale.

Dans le deuxième exemple, vous n'effectuez pas d'affectation à a, de sorte que le a global est utilisé.

Ceci est couvert par le 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

Je me demande pourquoi ils ont décidé de le décrire comme une «bizarrerie spéciale»? Contraste avec javascript où 'a = 1' affecte automatiquement à la portée globale! La seule bonne chose à ce sujet est que vous pouvez reconnaître rapidement le code de déchet par les absences de 'var a = 1' – aaronasterling

1

La question est une de mise à jour.

Vous ne pouvez pas mettre à jour a car ce n'est pas une variable dans l'espace de noms local de votre fonction. L'opération d'attribution de mise à jour sur place ne parvient pas à mettre à jour a sur place. De manière intéressante, a = a + 1 échoue également.

Python génère un code légèrement optimisé pour ce type d'instructions. Il utilise une instruction "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   

Notez que l'utilisation de a sur le côté gauche et à droite du signe égal conduit à cette optimisation.

Vous pouvez cependant accéder à a car Python recherche les espaces de noms locaux et globaux pour vous.

Étant donné que a n'apparaît pas du côté gauche d'une instruction d'affectation, un type d'accès différent est utilisé, "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 est équivalent à a = a + 1. En affectant à la variable a, il est rendu local. La valeur que vous tentez d'affecter a + 1 échoue car a n'a pas encore été lié.

0

C'est une très Gotcha Python commun: si vous attribuez à une variable dans une fonction (comme vous le faites, avec +=), où que ce (pas nécessairement avant de l'utiliser d'une autre manière), il ne utilisez le mondial. Cependant, puisque ce que vous faites est effectivement "a = a + 1", vous essayez d'accéder à a (sur le côté droit de l'expression) avant de l'assigner. Essayez d'utiliser global a au début de votre fonction (mais sachez que vous écraserez la valeur globale a).

Dans votre deuxième exemple, vous n'attribuez pas la variable a, mais uniquement l'un de ses éléments. Donc le dict global a est utilisé.

Questions connexes