Python Gotchas with Get
What is
x
?
There comes a time in every programmer’s life where she feels like a program or language is “out to get her”. This is what I eventually came to recognize as a gotcha, or “a feature of a system, a program or a programming language that works in the way it is documented but is counter-intuitive and almost invites mistakes”.
I was recently gotten by a Python convenience function, dict.get(key[, default])
, which you might use if you’re working with dictionaries. Let’s make sure it doesn’t get you, too!
The Dictionary
Python has a useful data structure, the dictionary, which is “best [thought of] as an unordered set of key:value pairs”. The cool thing about dictionaries is that they associate almost any one thing to another (whereas a list only associated an index with a value – see Learn Python the Hard Way). With a dictionary, you can store a value with a key, extract a value with a key, or delete a value with a key.
Let’s store a few values to a few keys.
You can add values
and get them with the same subscript syntax.
What happens when we try to get the value for a key that doesn’t exist?
There are some cases where, instead of a KeyError
, we have a default value for keys that are missing from a dictionary. That’s where get
comes in handy.
dict.get(key[, default]))
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError. The Python Standard Library
Let’s say we have a dictionary to keep track of animal sightings. This dictionary has animal names as keys and an integer value for number of sightings.
We want to check whether there have been sightings of the fabled Front-Facing Baby Chick (🐥) lately, but we’re not sure that it’s been stored in the dictionary as a key. We also know that if Front-Facing Baby Chick
isn’t a key in the dictionary, we should assume that it has been sighted 0
times.
This is where we use get
.
Awesome! Now we can get a default value from a key instead of a KeyError
. This is also much more readable than:
or
Here’s Where They Get You
Your Pythonista friend, Alice, thought she saw a Front-Facing Baby Chick (🐥) but then realized it was a run of the mill Baby Chick (🐤), and she thought that her mistake probably invalidated everyone else’s sightings, too.2 This is how she chose to record it.
What do you think happens now?
Hypothesis: get
tries to find the value associated with Front-Facing Baby Chick
, and since the value is None
, it uses the default value passed in as a parameter, 0
.
Not 0
, but None
. Why?
Under the covers, the implementation of get
might look something like this:
not
Which makes sense. If you call dict.get("Front-Facing Baby Chick", False)
, we don’t get a KeyError
– we get None
, which was a value in the dictionary. Getting a value None
associated with a key is different from the key not being in the dictionary, and get
does exactly what the docs say: “return the value for key if key is in the dictionary”.
So next time you try to specify a default, non-None
value for a key that might be in a dictionary, remember that getting None
back will still be possible.
Don’t let them get you 🐥.
Discussion
Is there ever a reason to set a key’s value to None
in a dictionary?
What are your favorite gotchas to watch out for?
-
X = None ↩
-
While Alice decided that her mistake invalidated
Front-Facing Baby Chick
sightings, she didn’t then attribute the sightings ofFront-Facing Baby Chick
to sightings of the regularBaby Chick
. She just chose to set one key toNone
. This is mainly a thought exercise, and hopefully you will not encounter Pythonista friends who set keys toNone
.
Instead of storing a value,None
, to a key, Alice probably should have decremented the value by 1 or deleted the key. ↩