Search code examples
pythondefaultdict

Can you explain this behavior with Python defaultdict and autovivification


I'm not sure if I'm missing something trivially obvious here but I can't for the life of me work out how the code below manages to give the output it does.

import collections

tree = collections.defaultdict(dict)
tree[0][1] = tree[1]
print tree
tree[1][2] = tree[2]
print tree

And here's the magical output:

defaultdict(<type 'dict'>, {0: {1: {}}, 1: {}})
defaultdict(<type 'dict'>, {0: {1: {2: {}}}, 1: {2: {}}, 2: {}})

The first line of output makes total sense. Consider then, the assignment tree[1][2] = tree[2] and its subsequent output.

I understand that the entry 2: {} has been created by evaluating the RHS expression tree[2].

I also understand the the entry 1: {2: {}} is created be evaluating the LHS expression tree[1][2] and assigning it to the value of the RHS.

What I don't understand, is how the dictionary entry 0: {1: {}} has been updated to 0: {1: {2: {}}} when no reference to tree[0] was made.


Solution

  • Because when you do tree[0][1] = tree[1] , tree[0][1] is referencing the same object as tree[1] , so if any changes happen inside tree[1] , it will also reflect in tree[0][1].

    And, when you do tree[1][2] , you are actually making changes inside tree[1] , and not making tree[1] reference a new object.

    Example , after your changes try to do this -

    >>> tree[1]['blah'] = 'Hello'
    >>> print(tree)
    defaultdict(<class 'dict'>, {0: {1: {2: {}, 'blah': 'Hello'}}, 1: {2: {}, 'blah': 'Hello'}, 2: {}})
    

    Only if you do something like - tree[1] = <somethingelse> , you are making tree[1] reference a new object, in which case it would not reflect in tree[0][1] .