3

I've ran into this behavior a couple times in Python and it's a little puzzling.

class MyClass:
    def __init__(self, initial_data={}):
        self.data = initial_data

instance_a = MyClass()
instance_a.data['key1'] = 'val1'
print("instance_a.data:", instance_a.data)

instance_b = MyClass()
print("instance_b.data:", instance_b.data)

With the output:

instance_a.data: {'key1': 'val1'}
instance_b.data: {'key1': 'val1'}

I would expect data to act as an instance variable, but it looks like in this case it acts as a class variable.

Does anyone know exactly why this happens and what's the best practice to avoid it?

cselig
  • 33
  • 2

2 Answers2

2

Because the id of the data variable is same. Functions in Python are first-class objects, and not only a piece of code.

print(id(instance_a.data))
# prints of object id

print(id(instance_b.data))
# prints the same object id

This is because of the fixed value in the parameter of the constructor. It does not create a new dictionary for each object.

On doing this:

def __init__(self):
    self.data = {}

You will get different results.

Read more here: http://effbot.org/zone/default-values.htm

Hope this helps, good luck.

Harshal Parekh
  • 5,918
  • 4
  • 21
  • 43
2

When assigning self.data = initial_data, you just create another new name for the object initial_data.

The behavior you didn't expect here is caused by the fact that the default argument initial_data gets evaluated only once when the method gets declared, not everytime you call it, so all your instances that use it actually use the same initial_data dict object, that you can access under different names like instance_a.data, instance_b.data and so on.

The classic solution is to use None as default, like this:

class MyClass:
    def __init__(self, initial_data=None):
        if initial_data is None:
            initial_data = {}
        self.data = initial_data
Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50