2010-04-19 6 views
4

Jetez un coup d'oeil à cet exemple simple. Je ne comprends pas pourquoi o1 imprime "Hello Alex" deux fois. Je pense qu'en raison de la valeur par défaut, self.a est toujours réinitialisé à la liste vide. Quelqu'un pourrait-il m'expliquer quelle est la logique ici? Merci beaucoup.Simple python oo numéro

class A(object): 
     def __init__(self, a=[]): 
      self.a = a 

o = A() 
o.a.append('Hello') 
o.a.append('Alex') 
print ' '.join(o.a) 

# >> prints Hello Alex 

o1 = A() 
o1.a.append('Hello') 
o1.a.append('Alex') 
print ' '.join(o1.a) 

# >> prints Hello Alex Hello Alex 
+1

cela est même mentionné dans la documentation: http://docs.python.org/tutorial/controlflow.html#default-argument-values ​​-> "Avertissement important" - à quel point cela doit-il être évident? – hop

+1

pas si évident et tout à fait contre-intuitif. –

Répondre

6

arguments par défaut dans Python, comme:

def blah(a="default value") 

sont évalués une fois et réutilisée dans chaque appel, de sorte que lorsque vous modifiez un vous modifiez un niveau mondial. Une solution possible est de faire:

def blah(a=None): 
    if a is None 
    a = [] 

Vous pouvez en savoir plus sur cette question: http://www.ferg.org/projects/python_gotchas.html#contents_item_6

Fondamentalement, ne jamais utiliser des objets mutables, comme des listes ou des dictionnaires sur une valeur par défaut pour un argument.

12

Lisez ce Pitfall sur les arguments de la fonction par défaut mutables: http://www.ferg.org/projects/python_gotchas.html

En bref, lorsque vous définissez

def __init__(self,a=[]) 

La liste référencée par self.a par défaut est définie une seule fois, à définition-time, pas d'exécution. Ainsi, chaque fois que vous appelez o.a.append ou o1.a.append, vous modifiez la même liste.

La façon typique de résoudre ce problème est de dire:

class A(object): 
    def __init__(self, a=None): 
     self.a = [] if a is None else a 

En déplaçant self.a=[] dans le corps de la fonction __init__, une nouvelle liste vide est créé au moment de l'exécution (chaque fois __init__ est appelé), pas au moment de la définition.

+0

Corrigez-le comme ceci: 'classe A (Object): def __init __ (auto, a = None): self.a = a si a n'est pas None else []' – badp

+0

Merci, bp, :-) – unutbu