2010-05-22 4 views
2

J'ai donc une erreur très étrange en ce moment. J'ai trouvé où cela arrive, et voici le code le plus simple qui peut le reproduire.Problèmes de portée Python uniquement lorsque _assigning_ à une variable

def cause_an_error(): 
    some_var = False 
    def some_nested_func(): 
     print some_var 
     #some_var = True 
    some_nested_func() 

>>> cause_an_error() 
False 

Si vous l'exécutez tel quel, il affiche "Faux". Mais si vous supprimez cette ligne, il donne une erreur:

Traceback (most recent call last): 
    File "<pyshell#224>", line 1, in <module> 
    cause_an_error() 
    File "<pyshell#223>", line 6, in cause_an_error 
    some_nested_func() 
    File "<pyshell#223>", line 4, in some_nested_func 
    print some_var 
UnboundLocalError: local variable 'some_var' referenced before assignment 

Notez l'erreur se produit sur la ligne qui travaillé très bien avant.

Des idées sur ce qui cause cela et comment je peux résoudre ce problème? J'utilise Python 2.6.1.

+0

très similaire à ce http://stackoverflow.com/questions/2516652/scoping-problem-in-recursive-closure –

Répondre

1

La fonction interne, some_nest_func, a sa propre portée et le fait que vous affectez à some_var quelque part dans cette portée rend some_var local à cette étendue. Cela a pour effet de masquer le some_var affecté dans la fonction externe. Ce sont deux variables différentes. Le résultat de tout cela est que vous imprimez la version de de some_var avant de l'assigner.

Si vous avez besoin de manipuler une variable à la fois à l'intérieur et à l'extérieur de la fonction interne, il n'y a pas de chemin propre, AFAIK. Un simple contournement consiste à remplacer la variable par un tableau à un seul élément et à le manipuler (ne l'attribuez pas à la variable de tableau, bien sûr).

+0

Cela a du sens pour moi. Mais la variable non-locale ne devrait-elle pas être ombrée * après * l'affectation? – Ponkadoodle

+1

L'observation se produit au moment de la compilation. Si Python trouve une affectation n'importe où dans la portée, toutes les références deviennent locales. –

+0

Hrmm. Alors, comment puis-je contourner cela? – Ponkadoodle

1

Ceci ne peut pas être corrigé dans 2.x sans refactoriser le code. 3.x ajoute nonlocal pour résoudre ce problème.

0

Vous pouvez le faire en changeant une valeur d'une référence (lire mutable) variables telles que dict, bien que laid, cette solution (transcrit à partir an answer to a similar question) devrait fonctionner:

def avoid_an_error(): 
    D = {"some_var": False} 
    def some_nested_func(): 
     D["some_var"] = True 
     print D["some_var"] 
    some_nested_func() 

>>> avoid_an_error() 
True