web-dev-qa-db-fra.com

Python constructeur et valeur par défaut

D'une manière ou d'une autre, dans la classe Node ci-dessous, les variables wordList et adjacencyList sont partagées entre toutes les instances de Node.

>>> class Node:
...     def __init__(self, wordList = [], adjacencyList = []):
...         self.wordList = wordList
...         self.adjacencyList = adjacencyList
... 
>>> a = Node()
>>> b = Node()
>>> a.wordList.append("hahaha")
>>> b.wordList
['hahaha']
>>> b.adjacencyList.append("hoho")
>>> a.adjacencyList
['hoho']

Est-il possible de continuer à utiliser la valeur par défaut (liste vide dans ce cas) pour les paramètres du constructeur mais pour obtenir à la fois a et b d'avoir leur propre wordList et adjacencyList variables?

J'utilise python 3.1.2.

100
Hery

Les arguments par défaut mutable ne font généralement pas ce que vous voulez. Au lieu de cela, essayez ceci:

class Node:
     def __init__(self, wordList=None, adjacencyList=None):
        if wordList is None:
            self.wordList = []
        else:
             self.wordList = wordList 
        if adjacencyList is None:
            self.adjacencyList = []
        else:
             self.adjacencyList = adjacencyList 
122
Michael J. Barber

Illustrons ce qui se passe ici:

Python 3.1.2 (r312:79147, Sep 27 2010, 09:45:41) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo:
...     def __init__(self, x=[]):
...         x.append(1)
... 
>>> Foo.__init__.__defaults__
([],)
>>> f = Foo()
>>> Foo.__init__.__defaults__
([1],)
>>> f2 = Foo()
>>> Foo.__init__.__defaults__
([1, 1],)

Vous pouvez voir que les arguments par défaut sont stockés dans un tuple qui est un attribut de la fonction en question. Cela n'a en fait rien à voir avec la classe en question et va pour n'importe quelle fonction. Dans python 2, l'attribut sera func.func_defaults.

Comme d'autres afficheurs l'ont souligné, vous souhaiterez probablement utiliser None comme valeur sentinelle et attribuer à chaque instance sa propre liste.

29
aaronasterling
class Node:
    def __init__(self, wordList=None adjacencyList=None):
        self.wordList = wordList or []
        self.adjacencyList = adjacencyList or []
17
Shankar Cabus

Je voudrais essayer:

self.wordList = list(wordList)

pour le forcer à faire une copie au lieu de référencer le même objet.

16
krousey