2011-01-30 9 views
73

Jakoś w poniższej klasie węzła zmienna wordList i adjacencyList jest współdzielona między wszystkimi instancjami węzła.Konstruktor języka Python i wartość domyślna

>>> 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'] 

Czy jest jakiś sposób mogę nadal używać wartości domyślnej (pusta lista w tym przypadku) dla parametrów konstruktora, ale aby dostać zarówno A i B mają własne wordlist i adjacencyList zmienne?

Używam Pythona 3.1.2.

+1

możliwe duplikat [W jaki sposób należy zadeklarować wartości domyślne dla zmiennych instancji w Pythonie?] (Http://stackoverflow.com/questions/2681243/how-should-i-declare-default-values-for- instance-variables-in-python) –

+0

Możliwy duplikat ["Least Astonishment" w języku Python: w którym zakresie znajduje się argument Mutable Default?] (http://stackoverflow.com/questions/1132941/least-astonishment-in-python -to-scope-is-the-mutable-default-argument-in) –

Odpowiedz

91

Zmienne domyślne argumenty zwykle nie robią tego, co się chce. Zamiast tego, spróbuj tego:

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 
+20

Mogą to być również one-liners: 'self.wordList = słowoList jeśli słowoLista nie jest Brak [] lub , trochę mniej bezpieczne, 'self.wordList = wordList lub []'. –

+1

To jest uważane za sposób Pythoniczny, ale ja wolę sposób Krousey, ponieważ "specjalne przypadki nie są wystarczająco szczególne". –

+0

@JoshBleecherSnyder Nie mogłem tego położyć na palcu, co czyni go mniej bezpiecznym niż ten pierwszy? – markdsievers

15

chciałbym spróbować:

self.wordList = list(wordList) 

zmusić go do wykonania kopii zamiast odwoływania się do tego samego obiektu.

+1

+1 dla prostoty :) – Hery

23

Zilustrujmy co się dzieje tutaj:

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],) 

Widać, że argumenty domyślne są przechowywane w krotki, która jest atrybutem funkcji w pytaniu. Faktycznie nie ma to nic wspólnego z klasą, o której mowa, i dotyczy dowolnej funkcji. W pythonie 2 atrybut będzie miał postać func.func_defaults.

Jak zaznaczyły inne plakaty, prawdopodobnie warto użyć None jako wartości wskaźnika i nadać każdej instancji swoją własną listę.

11
class Node: 
    def __init__(self, wordList=None adjacencyList=None): 
     self.wordList = wordList or [] 
     self.adjacencyList = adjacencyList or []