I like .attribute syntax as much as the next developer but the mutate-on-get behaviour strikes me as... undesirable.
Suppose I have an empty defaultdict(list). I do the following:
d = defaultdict(list)
l = d['foo']
According to no-mutate-on-get semantics, we now have an empty list, and d is still empty.
So what happens if I do: l.append('bar')
You might expect the dict to now be populated with {'foo': ['bar']}. However, the dict has no way of knowing (without a large amount of additional tricks) whether the new list that it previously returned had been later modified. So what would actually happen would be nothing, d would remain empty. Worse, now your behaviour is different depending on whether or not the 'foo' key was already present (if it was, you would've gotten a reference to the actual value and mutated it, and d would have changed as a result).As I see it, there are only two sane solutions to this problem: Either immediately store every generated value so any subsequent mutation is saved (the solution used here)...or require that your default values be immutable.
The mutate-on-get makes it very similar to how Matlab does its "structs", I'm mostly undecided on that but at times it can be nice.