Wednesday, May 12, 2010

list as default value in class __init__() - watchout for surprise

Note to self: don't use list as a default value in class methods if its going to be modified later, as it might cause some trouble.

Just realized something:

In [1]: class MyClass(object):
...: def __init__(self,data=[]):
...: self.data = data
...:
...: def addData(self,value):
...: self.data.append(value)
...:
...:

In [2]: obj = MyClass()

In [3]: obj.addData('hello')

In [4]: obj.data
Out[4]: ['hello']

In [5]: obj2 = MyClass()

In [6]: obj2.data
Out[6]: ['hello']

In [7]: obj3 = MyClass([])

In [8]: obj3.data
Out[8]: []


In [12]: def myfunc(val,data=[]):
....: data.append(val)
....: return data
....:

In [13]: myfunc(1)
Out[13]: [1]

In [14]: myfunc(2)
Out[14]: [1, 2]

In [15]: myfunc(3)
Out[15]: [1, 2, 3]


At first i thought its a bug/weirdness, but after banging my head a bit to wall and a long stare at the ceiling, it made sense.

During class definition, the list object already instantiated. Therefore, the default value of data variable is a reference to a list object, rather than a new list on each instantiation.

Not quite sure how to explain this in words ..

In [1]: class MyClass(object):
...: def __init__(self,data=[]): # data->List object at 0x0001
...: self.data = data # self.data->List object at 0x0001
...:
...: def addData(self,value):
...: self.data.append(value) # self.data->List object at 0x0001
...:
...:

In [2]: obj = MyClass()

In [3]: obj.addData('hello')

In [4]: obj.data # obj.data->List object at 0x0001
Out[4]: ['hello']

In [5]: obj2 = MyClass()

In [6]: obj2.data # obj2.data->List object at 0x0001
Out[6]: ['hello']

In [7]: obj3 = MyClass([]) # []->List object at 0x0002

In [8]: obj3.data # obj3.data->List object at 0x0002
Out[8]: []


I think you got the idea.
Post a Comment
Locations of visitors to this page