user1267132
user1267132

Reputation: 49

Unexpected behaviour when using dictionary inside class

I'll put the code first:

Python 2.7.3 (default, Aug  1 2012, 05:16:07) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.

>>> class Item(object):
...     def __init__(self, name, value={}):
...         self.name = name
...         self.value = value
...     def __str__(self):
...         return self.name + " - " + str(self.value)
...     def addValues(self, value):
...         for key,price in value.iteritems():
...             self.value[key] = price
... 
>>> 
>>> item1 = Item('car')
>>> print item1
car - {}
>>> item2 = Item('truck')
>>> print item2
truck - {}
>>> item1.addValues({'blue':6000})
>>> print item1
car - {'blue': 6000}
>>> print item2
truck - {'blue': 6000}
>>> 

I created two instances of class Item, item1 and item2. Then, I changed the value of dictionary attribute on object item1 with addValues method. The problem is that, adding dictionary attribute of item1, also added the same value to the item2. Can someone explain what is happening here? How did changing value on item1 changed the value on item2? Did I overlooked something?

Upvotes: 0

Views: 95

Answers (1)

arshajii
arshajii

Reputation: 129477

Default parameters are only evaluated once. The value parameter of your init will always be the same dictionary, so the effect of mutating it once when dealing with one Item instance will show up in all other Item instances as well.

From docs.python.org/2/reference/compound_stmts.html:

Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call. This is especially important to understand when a default parameter is a mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default value is in effect modified. This is generally not what was intended. A way around this is to use None as the default, and explicitly test for it in the body of the function, e.g.:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

Upvotes: 1

Related Questions