Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between defaultdict(lambda:None) and defaultdict(int)

What exactly does the TYPE lambda do when used with defaultdict? I have this example and works fine even for int, list & lambda as argument:

d = defaultdict(int)
d['one'] = lambda x:x*x
d['one'](2)
4

d = defaultdict(list)
d['one'] = lambda x:x*x
d['one'](2)
4

d = defaultdict(lambda: None)
d['one'] = lambda x:x*x
d['one'](2)
4

I have the same result each time. So what is the main reason to initialize with lambda "default (lambda: None)"? Looks defaultdict dictionary does not care about the what TYPE of argument is passed in.

like image 259
rva Avatar asked Nov 22 '15 16:11

rva


People also ask

What does Defaultdict Lambda 0 mean?

defaultdict takes a zero-argument callable to its constructor, which is called when the key is not found, as you correctly explained. lambda: 0 will of course always return zero, but the preferred method to do that is defaultdict(int) , which will do the same thing.

What is Defaultdict INT?

A defaultdict works exactly like a normal dict, but it is initialized with a function (“default factory”) that takes no arguments and provides the default value for a nonexistent key. A defaultdict will never raise a KeyError. Any key that does not exist gets the value returned by the default factory.

What does Defaultdict int do in Python?

The Python defaultdict type behaves almost exactly like a regular Python dictionary, but if you try to access or modify a missing key, then defaultdict will automatically create the key and generate a default value for it. This makes defaultdict a valuable option for handling missing keys in dictionaries.

What is the difference between Defaultdict and dict?

The difference is that a defaultdict will "default" a value if that key has not been set yet. If you didn't use a defaultdict you'd have to check to see if that key exists, and if it doesn't, set it to what you want. The lambda is defining a factory for the default value.


2 Answers

Your example only makes sense when you access keys that are not explicitly added to the dictionary:

>>> d = defaultdict(int)
>>> d['one']
0
>>> d = defaultdict(list)
>>> d['one']
[]
>>> d = defaultdict(lambda: None)
>>> d['one'] is None
True

As you can see, using a default dict will give every key you try to access a default value. That default value is taken by calling the function you pass to the constructor. So passing int will set int() as the default value (which is 0); passing list will set list() as the default value (which is an empty list []); and passing lambda: None will set (lambda: None)() as the default value (which is None).

That’s what the default dictionary does. Nothing else.

The idea is that this way, you can set up defaults which you don’t need to manually set up the first time you want to access the key. So for example something like this:

d = {}
for item in some_source_for_items:
    if item['key'] not in d:
        d[item['key']] = []

    d[item['key']].append(item)

which just sets up a new empty list for every dictionary item when it is accessed, can be reduced to just this:

d = defaultdict(list)
for item in some_source_for_items:
    d[item['key']].append(item)

And the defaultdict will make sure to initialize the list correctly.

like image 131
poke Avatar answered Sep 17 '22 23:09

poke


You are not using the default value factory. You won't see a difference if all you do is assign to keys, rather than try and retrieve a key that isn't in the dictionary yet.

The default value factory (the first argument to defaultdict()) is not a type declaration. It is instead called whenever you try and access a key that isn't in the dictionary yet:

>>> from collections import defaultdict
>>> def demo_factory():
...     print('Called the factory for a missing key')
...     return 'Default value'
...
>>> d = defaultdict(demo_factory)
>>> list(d)  # list the keys
[]
>>> d['foo']
Called the factory for a missing key
'Default value'
>>> list(d)
['foo']
>>> d['foo']
'Default value'
>>> d['bar'] = 'spam'  # assignment is not the same thing
>>> list(d)
['foo', 'bar']
>>> d['bar']
'spam'    

Only the first time when I tried to access the key 'foo' was the factory called to produce a default value, which is then stored in the dictionary for future access.

So for each of your different examples, what varies between them is what default value will be produced for each. You never access this functionality, because you directly assigned to the 'one' key.

Had you accessed a non-existing key you'd have created an integer with value 0, an empty list or None, respectively.

like image 41
Martijn Pieters Avatar answered Sep 17 '22 23:09

Martijn Pieters