Python constructor and default value

PythonConstructorDefault Value

Python Problem Overview


Somehow, in the Node class below, the wordList and adjacencyList variable is shared between all instances of 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']

Is there any way I can keep using the default value (empty list in this case) for the constructor parameters but to get both a and b to have their own wordList and adjacencyList variables?

I am using python 3.1.2.

Python Solutions


Solution 1 - Python

Mutable default arguments don't generally do what you want. Instead, try this:

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 

Solution 2 - Python

Let's illustrate what's happening here:

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

You can see that the default arguments are stored in a tuple which is an attribute of the function in question. This actually has nothing to do with the class in question and goes for any function. In python 2, the attribute will be func.func_defaults.

As other posters have pointed out, you probably want to use None as a sentinel value and give each instance it's own list.

Solution 3 - Python

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

Solution 4 - Python

I would try:

self.wordList = list(wordList)

to force it to make a copy instead of referencing the same object.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHeryView Question on Stackoverflow
Solution 1 - PythonMichael J. BarberView Answer on Stackoverflow
Solution 2 - PythonaaronasterlingView Answer on Stackoverflow
Solution 3 - PythonShankar CabusView Answer on Stackoverflow
Solution 4 - PythonkrouseyView Answer on Stackoverflow