1

when defaultdict is configured to instantiate a class, the behaviour is different if the class has default parameters.

As an example, this is the expected behaviour:

from typing import List
from collections import defaultdict

class Test:
    def __init__(self):
        self.values = []

tests = defaultdict(Test)

tests['a'].values.append(1)
tests['b'].values.append(2)

print([f"{id}: {t.values}" for id, t in tests.items()]) #--> ['a: [1]', 'b: [2]']

Now, when the class has a default value, all objects share the same reference:

class Test:
    def __init__(self, values = []):
        self.values = values

tests = defaultdict(Test)

tests['a'].values.append(1)
tests['b'].values.append(2)

print([f"{id}: {t.values}" for id, t in tests.items()]) #--> ['a: [1, 2]', 'b: [1, 2]']

This happens only if the parameter is a reference, so for example:

class Test:
    def __init__(self, values = 0):
        self.values = values

tests = defaultdict(Test)

tests['a'].values += 1
tests['b'].values += 1

print([f"{id}: {t.values}" for id, t in tests.items()]) #--> ['a: 1', 'b: 1']

Why is that?

pief
  • 25
  • 5

1 Answers1

1

this occurs because defaults are evaluated precisely once when the function is defined, not every time it's called.

https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments

and to clarify, all vars in python are references. it's just that some things they refer to are mutable and some aren't.

acushner
  • 9,595
  • 1
  • 34
  • 34