Python Dicts: Most Common Exceptions and How to Avoid Them!

In this article, let us learn about the common exceptions in the Dictionaries class in Python, and how to deal with them.

Let’s face it, no programmer is expected to write perfect and flawless Python code that executes without any errors the first time.

Some mistakes are more common than others, as the code does not really behave that we intuitively expect it to. These mistakes are commonly denoted using the term “Pitfalls” and this article is all about looking at the pitfalls when working with Python Dictionaries

Feel free to jump to the section of interest using the table of contents below.

Let us start by refreshing our memories!

Python Dictionaries: A Refresher

A dictionary is a data structure that is used to store Key-Value pairs.

You can create a dictionary

  • by using the dict() constructor or
  • by using the curly braces {} notation.

Here’s an example that shows both these notations.

# Creating a dictionary using the curly braces notation, each item is a key:value pair
my_dict = {1: "Embedded", 2: "Inventor"}

# Creating a dictionary using the dict() constructor and a list of tuple where each tuple is a (key, value) pair.
my_dict = dict([(1, "Embedded"), (2, "Inventor")])

Both these notations produce the exact same dictionary, the one shown in the figure below.

All keys in a dictionary must be unique and of an immutable type (e.g. strings or numbers), but values can be anything, by anything here I mean any datatype, mutable or immutable. Since you can store any type of value in dictionaries, it is useful in numerous situations as you will experience at various points in your career as a Python programmer!

For example, let’s say you want to store some info about the famous Ringo Starr. You can simply do it like this:

ringo_starr = {"dob": "07 Jul 1940", "band":"The Beatles", "instruments":["drums","vocals"]}

To access a value in a dictionary, you just use the key in square brackets. So if you want to know Ringo’s date of birth, you can do this:

print(ringo_starr["dob"])  # Output: "07 Jul 1940"

You can also nest dictionaries within dictionaries, which lets you store even more information in a hierarchical way. For example:

ringo_starr = {"dob": "07 Jul 1940", "band":"The Beatles", "instruments {"primary":"drums", "secondary":"vocals"}}

I hope now you feel ready to move on to the next part. If anything in this section feels hazy to you I recommend reading our other article which is dedicated to the understanding of Python Dictionaries.

Common errors faced when working with Dictionaries in Python

Before looking at the errors themselves, lets have another quick refresher, this time on the topic of Exceptions!

The Fundamentals: Exceptions, What are they?

If you fill your car’s fuel tank with water instead of gas, the engine will have no idea what to do with it and the engine will simply refuse to run.

Similarly, when the “Python interpreter” (the engine) does not know what to do with the “data” (water) that we gave it, the program will get stuck. The Exception object is just an error report generated by the interpreter giving us clues on

  • what went wrong? and
  • where in the program the problem is?

Sure there is more to Exception than that, but their main use is to give us clues. So the next time when you think about exceptions, think of a them as clues to solve an issue!

If you feel that your basics could use some boosting, I suggest reading the following article

Exceptions in Python: Everything You Need To Know!

If you are a visual learner, here is an interesting video we made on that topic!

Alright, now that we have refreshed our basics, lets get back to the topic and start by looking at the KeyError exception!

Pitfall#1: Program crashes with KeyError Exception

This is by far the most common mistake seen with Python beginners.

This pops up when we try to use a key that doesn’t exist in Python. When you see a KeyError, it simply means that the key being looked for could not be found.

Let’s use the hongkong example and call for a key that doesn’t exist:

hongkong= {"Country":"China", 
           "Population":7500000, 
           "Attractions":[ "Man Mo Temple", "Victoria Harbor"],
           “Country Capital":False
          }
hongkong['Official Language']

This results in the following error message:

Traceback (most recent call last):
  File "main.py", line 8, in <module>
    hongkong['Official Language']
KeyError: 'Official Language'

We can see the bottom line of the error message and make two conclusions:

  1. The error is called KeyError
  2. The key that caused it is called ‘Official Language’

Note: When an exception is raised in Python, it is done with a traceback. The traceback gives you all the relevant information to be able to determine why the exception was raised and what caused it.

Learning how to read a Python traceback and understanding what it is telling you is crucial to improving as a Python programmer.

If you wish to learn more about Exceptions we have an excellent article on our website to serve you!

Usually, to access the value of a key, we simply use the following:

hongkong= {"Country":"China", 
           "Population":7500000, 
           "Attractions":[ "Man Mo Temple", "Victoria Harbor"],
           “Country Capital":False
          }
Dict_name[key_name]

If I wanted to get the population of Hong Kong:

hongkong= {"Country":"China", 
           "Population":7500000, 
           "Attractions":[ "Man Mo Temple", "Victoria Harbor"],
           “Country Capital":False
          }

print(hongkong["population"])

OUTPUT

7500000

Another way to get this value is by using the get() method. Have a look at the following code:

hongkong= {"Country":"China", 
           "Population":7500000, 
           "Attractions":[ "Man Mo Temple", "Victoria Harbor"],
           “Country Capital":False
          }

print(hongkong.get("population"))

OUTPUT

7500000

We suggest using the get() method whenever you are unsure whether a key is really present in the dictionary or not. This is because even though both return values as we want, they are internally wired a little bit differently.

Let us see how the get() method behaves differently using an example. Let’s say I want to get the Time Zone of Hong Kong using the get() method.

>>> print(hongkong.get("timezone"))
None

This is as expected since we did not define a key called timezone in our dictionary

However, if I do the same with the first method:

>>> print(hongkong["timezone"])
Traceback (most recent call last):
  File "main.py", line 8, in <module>
    print(hongkong["timezone"])
KeyError: 'timezone'

We see that we’ve encountered the KeyError exception.

This is the difference between the usual direct access and using the get() method.

The get() method does not return an error when it does not find a value we asked for whereas using the direct method causes the program to pop up an error, this stops the execution of the program altogether, which is simply bad design!

Pitfall#2: Program crashes with ValueError Exception

This arises when we use the update() method incorrectly.

The update() method adds the contents of one dictionary to another. Have a look at the following example:

# vehicles are driven on the left side of the road in Hong Kong
hk_driv_side = {"Road Driving Side": "Left"}
hongkong.update(hk_driv_side)
print(hongkong)

OUTPUT

{'Country': 'China', 'Population': 7500000, 'Attractions': ['Man Mo Temple', 'Victoria Harbor'], 'Country_Capital': False, 'Road Driving Side': 'Left'}

We can see that the original dictionary has been updated! This is how the dict.update() method works.

However as mentioned earlier, when it is used incorrectly. It leads to a ValueError. For instance, take a look at the following example where I try to add the same Road Driving Side key

hongkong= {"Country":"China", 
                     "Population":7500000, 
                     "Attractions":[ "Man Mo Temple", "Victoria Harbor"],
                     "Country Capital":False}

# vehicles are driven on the left side of the road in Hong Kong
hk_driv_side = {"Left"}
hongkong.update(hk_driv_side)
print(hongkong)

OUTPUT:

Traceback (most recent call last):
  File "main.py", line 9, in <module>
    hongkong.update(hk_driv_side)
ValueError: dictionary update sequence element #0 has length 4; 2 is required

This is incorrect and resulted in an error because The dict.update() method can be called with a dictionary or an iterable of key/value pairs such as a list of tuples containing 2 elements:

# a list of tuples
hongkong.update([("Road Driving Side","Left")])

Pitfall#3: Copying Dictionaries Incorrectly

If you come from programming languages like C, when you are trying to copy over one variable to another you will intuitively do it the way shown below.

>>> myDict = {1:'a', 2:'b'}
>>> myDictCopy = myDict
>>> myDict
{1: 'a', 2: 'b'}
>>> myDictCopy
{1: 'a', 2: 'b'}

As you can see, both myDict and myDictCopy contain the same values, which is also what we intuitively expect the code to do. But what happens when we try to edit one?

>>> myDictCopy[1] = 'A' # Editing the copy
>>> myDictCopy
{1: 'A', 2: 'b'}
>>> myDict
{1: 'A', 2: 'b'} # Original also changes!

As you can see when we try to edit myDictCopy, myDict also changes! This is definitely not what we wanted the code to do!

So what happened here?

When we wrote the statement

myDictCopy = myDict

what we essentially did was, we created 2 names to refer to the same dictionary.

Just like a person can have an official name and a nickname and both are still referring to the same person, in Python when we use the assignment operator “=” we are essentially creating another name to refer to the same object in memory.

This is illustrated in the figure below.

In works of literature about programming languages, instead of using the word “name“, we use the word “reference” instead as it is referring to an object!

So how to actually create a copy then?

For this Python provides us with the copy() method which is designed to create 2 copies just the way we want. Have a look at the following example

Let us see how to use the copy() method

>>> myDict = {1:'a', 2:'b'}
>>> myDictCopy = myDict.copy()
>>> myDict
{1: 'a', 2: 'b'}
>>> myDictCopy
{1: 'a', 2: 'b'}

As you can see we used the copy() method this time, now let us try editing the copy again!

>>> myDictCopy[1] = 'A'
>>> myDict
{1: 'a', 2: 'b'}
>>> myDictCopy
{1: 'A', 2: 'b'}

Nice! Only the copy changed and not the original!

Another way to create a copy is to use the dict() constructor as shown below.

new_dictionary = dict(old_dictionary)

This creates a completely independent dictionary just as with the copy() method. I let you experiment with this one yourself!

Is this a reference(2nd name) or a copy?

But is there a way to check if a given variable is just another name or is it a true copy?

In fact, there are 2 ways of doing this

Method#1: Using the “is” keyword in Python

The “is” keyword can be used to see if 2 names are referring to the same or different objects as shown below.

>>> myDict = {1:'a', 2:'b'}
>>> myDictCopy = myDict
>>> myDict is myDictCopy
True
>>> myDictCopy = myDict.copy()
>>> myDict is myDictCopy
False

As you can see

  • in line-2, we created a reference/2nd-name using the assignment operator.
  • in line-3, we used the “is” operator and we got “True” as they are both referring to the same object.
  • in line-5, we used the copy() method to make a copy
  • in line-6, we used the “is” operator again and this time we got “False” as they are both referring to 2 different objects!

If the above explanation leaves you with more questions than answers and if you wish to learn more about the “is” keyword (and its brother the “is not” keyword), we have an entire article dedicated to it which you can read here!

Method#2: Using the inbuilt id() function

The “is” keyword does the magic that it does using the inbuilt id() function.

Each object created in python has a unique number associated with it just like each automobile has a unique VIN number, as each phone has a unique IMEI number, and as each person has a unique passport number. This can be retrieved using the inbuilt id() function as shown below.

>>> myDict = {1:'a', 2:'b'}
>>> myDictCopy = myDict.copy()
>>> id(myDict)
2480565641216
>>> id(myDictCopy)
2480565709632

As you can see both copies have different id numbers. Now we can make a simple equality comparison to determine if 2 objects are the same or different as shown below.

>>> id(myDict) == id(myDictCopy)
False

If the double-equal-to “==” sign is not something that you have seen before I recommend heading over to the following article to learn more!

Python’s “==” Explained Using 12 Examples

The points we have discussed are summarized in the following table.

PitfallReasonSolution
KeyErrorTrying to access a key that doesn’t exist in the dictionaryUse the get() method to safely access a key and prevent the error
ValueErrorUsing the dict.update() method incorrectlyUse the update() method the correct way.
Copying the proper wayAssignment operator = produces a new reference and not a new objectUse the copy() method or the dict() constructor to create new objects

Here is another pro tip for you, to fix any error in Python. Whenever your program crashes with an Exception, (take a deep breath and) have a look at the huge wall of error text that just got printed on your screen!

There is actually a lot of information contained in the error message, if you wish to learn the tricks then set aside 10mins of your time and read the following article!

Python: Details contained in an Exception

For visual learners out there we have also made an interesting video on that topic!

Encountering errors is a part and parcel of programming, keep learning and hone your programming skills, which Embedded Inventor will always be helping in!

Here are some other articles that may be of interest to you.

Related articles

Python Dictionary: Explained!

Python Sets: Explained!

Python Lists: Explained!

Thanks to Namazi Jamal for his contributions to writing this article!

Photo of author
Editor
Balaji Gunasekaran
Balaji Gunasekaran is a Senior Software Engineer with a Master of Science degree in Mechatronics and a bachelor’s degree in Electrical and Electronics Engineering. He loves to write about tech and has written more than 300 articles. He has also published the book “Cracking the Embedded Software Engineering Interview”. You can follow him on LinkedIn