-1

I understand collections.defaultdict is assigning default value to a dict like this:

dict = collections.defaultdict(int) # default value of dict is 0

or

dict = collections.defaultdict(lambda: 5) # default value of dict is 5

Then I see a usage of defaultdict in Python like this:

_dict = lambda : collections.defaultdict(_dict)
dict = _dict()

dict = dict["A"]
dict = dict["B"]
dict = dict["C"]

I am very confused of the first line:

_dict = lambda: collections.defaultdict(_dict)

What is exactly the default value? It seems it is an endless recursion.

derek
  • 9,358
  • 11
  • 53
  • 94
  • 5
    Perhaps you forgot a `lambda` somewhere? See [How to convert defaultdict of defaultdicts \[of defaultdicts\] to dict of dicts \[of dicts\]?](//stackoverflow.com/q/26496831) for example, which uses a 'recursive' definition. The trick there is that `factory` is not looked up until you *call* `factory`, at which point the name exists.. – Martijn Pieters Aug 16 '17 at 17:59
  • @MartijnPieters forgot to add lambda ahead. See my updates – derek Aug 16 '17 at 18:01
  • Yes, it's recursive, but it's not endless. As Martijn said "The trick there is that `factory` is not looked up until you call `factory`". – PM 2Ring Aug 16 '17 at 18:04
  • All the lambda does is define a defaultdict that reuses the same factory. That just makes nested values a new defaultdict with the factory shared. That's not *endless*. It's called *auto-vivication*. – Martijn Pieters Aug 16 '17 at 18:09

1 Answers1

0

defaultdict() takes a factory, and will call the factory each time it needs a default value. If you pass in int, every time a new default value is needed, int() is called.

The code you found use a lambda as the factory. Every time you call it, it returns a new defaultdict(...) object. Now, the defaultdict() object still needs a factory, and in this case, it just reuses the same factory object.

This works, because the name _dict is only looked up when call the lambda, and you can only call the lambda once it is created and assigned to the name _dict; the dependency cycle works because the self-reference is only looked up after the reference has been created.

This is a lot like recursion, but not the same thing. Recursion automatically calls the same function until an end-condition breaks the call chain. But here, there is no automatic call chain! When you need a new default value, the lambda is called, and that returns a new defaultdict(_dict) object. And that's it. There is no automatic chain, the newly-minted defaultdict has a factory of it's own configured, but it is not automatically called.

The concept is called autovivication.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • when you say "the newly-minted defaultdict has a factory of it's own configured", does it mean it will return dict "{}"? Where is the default value "{}" returned exactly? – derek Aug 21 '17 at 16:35
  • @derek: no, it won't return `{}`. It's another `defaultdict` object, and if you try to access a non-existing key, it'll call the factory to produce a value. – Martijn Pieters Aug 21 '17 at 16:36
  • @derek: that factory then creates another `defaultdict` object, which has a factory configured. Etc. – Martijn Pieters Aug 21 '17 at 16:37