Search code examples
pythondictionarymutable

Default initializer points to same data for all instances of object?


A few days ago I had a nasty bug related to this issue: when my class's constructor has a default argument of an empty dictionary, all instances of that class point to the same dictionary. Here is an example:

class A:
    def __init__(self, d={}):
        self.D = d

class B:
    def __init__(self):
        self.D = {}

a1 = A()
a2 = A()
b1 = B()
b2 = B()

a1.D.update({'Akey':'Avalue'})
print("Printing a1 dict: ", a1.D)
print("Printing a2 dict: ", a2.D)

b1.D.update({'Bkey':'Bvalue'})
print("Printing b1 dict: ", b1.D)
print("Printing b2 dict: ", b2.D)

Ouput:

Printing a1 dict:  {'Akey': 'Avalue'}
Printing a2 dict:  {'Akey': 'Avalue'}
Printing b1 dict:  {'Bkey': 'Bvalue'}
Printing b2 dict:  {}

I suspect that when the dictionary is initialized inside the constructor (as in class B), it creates a new reference for each object. When the dictionary is initialized as a default object, even though it is initialized to the empty dictionary, all objects point to the same dictionary.

Can someone shed light on this behavior and explain more about the inner workings of it?

Thanks


Solution

  • From the Python Language Reference

    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.

    When the function is defined, an empty dictionary is created, and bound to the function object. The assignment statement

    self.D = d
    

    assigns the member variable to point to the instance created when the function was defined. Modifying that dictionary will modify the instance bound as the default value.

    An alternative definition that likely accomplishes your goal would be something like:

    def __init__(self, d=None):
        if d is None:
            self.D = {}
        else:
            self.D = d