2010-12-11 9 views
1

Pourquoi diable Python permet de changer la liste déclarée globale en fonction?Pourquoi changer global ne donne pas d'erreur?

réactualisées

numbers = [] 
num = 4 

def add(n, thisnum=None): 
    # changing global list without global declaration! 
    numbers.append(n) 
    if thisnum: 
     num = thisnum 
     print 'num assigned', thisnum 
    ##numbers = ('one', 'two', 'three') 
    ## adding this line makes error: 
"""Traceback (most recent call last): 
    File "J:\test\glob_vals.py", line 13, in <module> 
    add(i) 
    File "J:\test\glob_vals.py", line 6, in add 
    numbers.append(n) 
UnboundLocalError: local variable 'numbers' referenced before assignment 
""" 

for i in (1,2,3,564,234,23): 
    add(i) 

print numbers 
add(10, thisnum= 19) 
# no error 
print num 
# let the fun begin 
num = [4] 
add(10, num) 
print num 

# prints: 
"""[1, 2, 3, 56, 234, 23] 
num assigned 19 
4 
num assigned [4] 
[4] 

""" 

Si je mets assignement à la variable avec le même nom alors l'action avant cette ligne devient erreur, pas la ligne ajoutée (octet points du compilateur de code, je suppose).

+0

Vous semblez être confus au sujet des règles de portée. Il y a quelques questions à ce sujet avec des réponses de qualité réparties à travers SO, et docs.python.org couvre également cela. – delnan

+0

Je pense toujours que ce n'est pas chose triviale ou évidente de la documentation que j'ai étudiée beaucoup, étant enseignant et étudié l'informatique depuis 1984. –

+0

Je pense que c'est simple - peut-être plus complexe que les règles de portée dans la plupart des langues, mais toujours poignée de règles sans mauvaises exceptions. – delnan

Répondre

5

Vous n'attribuez pas à la variable globale, vous appelez une méthode qui modifie son contenu. Ceci est autorisé

Ce que vous ne pouvez pas faire sans le mot-clé global est ceci:

def add(n): 
    #global numbers 
    numbers = numbers + [n] 

Résultat:

 
Traceback (most recent call last): 
    File "C:\Users\Mark\Desktop\stackoverflow\python\test.py", line 8, in 
    add(i) 
    File "C:\Users\Mark\Desktop\stackoverflow\python\test.py", line 5, in add 
    numbers = numbers + [n] 
UnboundLocalError: local variable 'numbers' referenced before assignment 

La différence est que je ne suis pas ici la liste existante muter - Je suis en train pour créer une nouvelle liste et réaffecter à la portée globale. Mais cela ne peut pas être fait sans le mot-clé global.


En ce qui concerne votre mise à jour:

La ligne suivante est OK car il crée un nouveau nom local num dans le cadre de la fonction. Cela n'affecte pas la valeur de la variable à l'échelle globale.

num = thisnum 
0

Parce que vous êtes juste à une AJOUT DE liste.

L'accès et l'affectation sont des concepts différents. Lorsque vous ajoutez une liste, vous appelez simplement une méthode qui modifie sa valeur. Supposons que vous avez fait +=, ce serait l'assignation.

Si vous deviez le faire:

>>> numbers = [] 
>>> def add(n): 
     numbers += n 

>>> n = [1, 2] 
>>> add(n) 

Il échouerait parce que c'est la cession.

Pour résoudre ce problème, dans la fonction add(), vous ajoutez:

>>> def add(n): 
     global numbers 
     numbers += n 
1

global xseulement affests x = ... (à savoir, il fait ce réattribuer le x global au lieu de créer un x local indépendant). Il n'affecte pas x.member = ... (parce que c'est un appel de méthode) ou x.mutating_method(...), parce que Python (ce n'est pas un problème de statique vs dynamique, btw) ne peut pas savoir (et s'en fout) que ces méthodes modifient self d'une certaine façon - vous devriez donc empêcher les appels de méthode sur (les objets pointés par) les variables globales ... ce qui, bien sûr, est inutile.

En ce qui concerne la mise à jour: Lorsque vous faites num = thisnum, vous faites quelque chose de complètement différent numbers.append(n) - vous créez une variable locale (parce que vous n'avez pas fait global num) et en lui attribuant une certaine valeur.Cela ne touche même jamais le global num.

+0

Voir re-mise à jour, maintenant il ne le touche pas. –

+0

@Tony: Voir ma première phrase - Python suppose que 'x' est local s'il est assigné quelque part dans la fonction, et comme le message d'erreur vous le dit, le' numbers' local (c'est un local car il * est * assigné plus tard dans la fonction et non déclarée 'global') n'a aucune valeur qui lui est assignée à ce moment-là. – delnan

+0

Je comprends, mais ça fait un bel effet "retour vers le futur" qui fait que la ligne qui était OK avant échoue, à cause de la ligne suivante. Il souligne simplement l'existence d'une étape de compilation d'octets. Et passer dans la liste comme variable au lieu d'écrire la même valeur que l'argument direct donne un effet secondaire à l'appelant. –

Questions connexes