2009-07-28 9 views
3

J'ai un exemple trivial:problème portée Python


def func1(): 
    local_var = None 

    def func(args): 
     print args, 
     print "local_var:", local_var 

     local_var = "local" 

    func("first") 
    func("second") 

func1() 

Je me attends à la sortie soit:

 
first local_var: None 
second local_var: local 

Cependant, ma sortie réelle est:

 
first local_var: 
Traceback (most recent call last): 
    File "test.py", line 13, in 
    func1() 
    File "test.py", line 10, in func1 
    func("first") 
    File "test.py", line 6, in func 
    print "local_var:", local_var 
UnboundLocalError: local variable 'local_var' referenced before assignment 

Ma compréhension de Les règles de portée de Python dictent que cela devrait fonctionner comme prévu. J'ai un autre code où cela fonctionne comme prévu, mais réduire un fragment de code non fonctionnel à son cas trivial ci-dessus ne fonctionne pas non plus. Donc je suis perplexe.

Répondre

9

L'affectation à local_var dans func rend local à func - de sorte que l'instruction print référence que "très ve ry local "variable avant qu'il ne soit jamais assigné, comme l'indique l'exception. Comme dit jtb, dans Python 3 vous pouvez résoudre ceci avec nonlocal, mais il est clair à partir de votre code, en utilisant les instructions print, que vous travaillez dans Python 2. La solution traditionnelle dans Python 2 est de s'assurer que l'assignation n'est pas un barename et ne permet donc pas la variable plus locale que vous souhaitez, par exemple:

def func1(): 
    local_var = [None] 

    def func(args): 
     print args, 
     print "local_var:", local_var[0] 

     local_var[0] = "local" 

    func("first") 
    func("second") 

func1() 

l'affectation à l'indexation n'est pas à un barename et n'affecte donc pas lieu, et depuis Python 2.2, il est tout à fait acceptable pour les fonctions internes imbriquées à renvoient aux variables qui sont locales dans les fonctions contenant externes, ce qui est tout ce que fait cette version (assignant aux noms de barres est un problème différent que en référence aux variables).

+0

Merci! Cela explique pourquoi j'ai parfois eu le comportement attendu - quand je n'ai pas réaffecté ma variable locale dans la fonction (func() dans ce cas), tout allait bien. L'acte de l'assigner l'a rendu "très très local", comme vous le dites. –

1

Avant Python 3.0, les fonctions ne pouvaient pas écrire dans des variables non globales dans des étendues externes. Python3 a introduit le mot-clé nonlocal qui permet ce fonctionnement. Vous devez ajouter nonlocal local_var en haut de la définition de pour obtenir la sortie attendue. Voir PEP 3104.

Si vous ne travaillez pas en Python 3, vous devrez rendre la variable globale, ou la passer en quelque sorte dans la fonction.

1

La méthode standard pour résoudre ce problème pré-3.0 serait

def func1(): 
    local_var = [None] 

    def func(args): 
     print args, 
     print "local_var:", local_var[0] 

     local_var[0] = "local" 

    func("first") 
    func("second") 

func1()