chrips
chrips

Reputation: 5296

How can I read the syntax of this python dictionary insertion?

foods={}
name="potato"
foods[name]=foods.get(name, 0) +1
print(foods)

I'm creating a dictionary and a string. Then, next line, everything goes insane...

Suddenly it looks like we are supposing that the new string already exists in the new dictionary...

foods[name]=

As I understand from comments here, we're getting the Dictionary's key "name" with value 0,

foods.get(name, 0)

and adding one to the key's value.

+1

How can I reason this so it makes sense?

Related:

How can I add new keys to a dictionary?

Why dict.get(key) instead of dict[key]?

Upvotes: 0

Views: 42

Answers (2)

Tomerikoo
Tomerikoo

Reputation: 19414

Well I believe the first lines are obvious:

foods = {}
name = "potato"

The important thing to remember here is that dicts are mutuable objects.


Next, what we have is a dict assignment:

foods[name] = x

As described in How can I add new keys to a dictionary?, this basically says: "Associate the value x to the key name inside foods". If name already exists in foods with some value, that value will be overridden with x. If it does not exist in the dict, a new key:value pair will be created.

This will NEVER raise an error*, because we don't assume anything about the keys - it is not necessary. As explained above, if the key doesn't exist a new pair will be created. If the key exists already, it will be updated. Internally, the dict's __setitem__ method is called to allow this behaviour: foods[name] = x --> foods.__setitem__(name, x).


The value in this case is:

foods.get(name, 0) + 1

As described in Why dict.get(key) instead of dict[key]?, The get method is used if we don't want the code to fail if some keys are missing. It has an optional argument default (which its default is None). This means that dict.get(key, default) works the same as dict[key] as long as the key exists in the dict! If it doesn't exist already, then default will be returned instead.

So this line can be read as "add 1 to the value of name from foods if it exists in the dict, else just return 1 (0 + 1)". This is a common construct for implementing some counter. We can use this single line to replace the following cumbersome structure:

if name in foods:
    foods[name] += 1
else:
    foods[name] = 1

You can now see the direct replacement: If the key exists, get will return its value, then we add 1 and save it back to the dict - equivalent to foods[name] += 1. If it doesn't exist in the dict, get will return 0, then we add 1 to get 1, and save that in the dict - equivalent to foods[name] = 1.


Another alternative is to use a defaultdict with int type:

foods = defaultdict(int)
foods[name] += 1

This encapsulates all that logic and when a key doesn't exist in the dict and we try to access it, the type we provided is called to create a default value. In this case, int() returns 0 as desired.


* For hashable keys.

Upvotes: 2

gen_Eric
gen_Eric

Reputation: 227270

The dict.get() method takes 2 arguments: The key and a default value if that key doesn't already exist in the dict.

So foods.get(name, 0) means look up the name key in foods and return its value, otherwise return 0.

Upvotes: 2

Related Questions