Python Dictionary Comprehension: A Powerful One-Liner Tutorial

5/5 - (12 votes)

Dictionary Comprehension is a concise and memory-efficient way to create and initialize dictionaries in one line of Python code. It consists of two parts: expression and context. The expression defines how to map keys to values. The context loops over an iterable using a single-line for loop and defines which (key,value) pairs to include in the new dictionary.

Python Dictionary Comprehension - A Powerful One-Liner Tutorial

The following example shows how to use dictionary comprehension to create a mapping from women to men:

men = ['Bob', 'Frank', 'Pete']
women = ['Alice', 'Ann', 'Liz']

# One-Liner Dictionary Comprehension
pairs = {w:m for w, m in zip(women, men)}

# Print the result to the shell
# {'Bob': 'Alice', 'Frank': 'Ann', 'Pete': 'Liz'}

Next, you’ll dive into a short Python exercise to open and close your knowledge gaps and strengthen your intuitive understanding.

Interactive Python Shell

Execute the following one-liner dictionary comprehension in the interactive code shell:

Exercise: Change the code so that each value x maps to its cube x**3 for the first eleven values from 0 to 10 (inclusive)!

Related Article: Every Python master has also mastered the dictionary data structure. Check out our full tutorial on the Finxter blog here.

Next, you’ll dive even deeper into the powerful dictionary comprehension operator in a step-by-step manner!

Python Dictionary Comprehension Zip

Dictionary comprehension lets you create dictionaries in a clean, easy to understand and Pythonic manner. However, if you have two lists, you can create a dictionary from them using dict(zip())

names = ['Adam', 'Beth', 'Charlie', 'Dani', 'Ethan']
countries = ['Argentina', 'Bulgaria', 'Colombia', 'Denmark', 'Estonia']
dict_zip = dict(zip(names, countries))
>>> dict_zip
{'Adam': 'Argentina',
'Beth': 'Bulgaria',
'Charlie': 'Colombia',
'Dani': 'Denmark',
'Ethan': 'Estonia'}

You can also do this using a for loop

>>> new_dict = {}
>>> for name, country in zip(names, countries):
        new_dict[name] = country
>>> new_dict
{'Adam': 'Argentina',
'Beth': 'Bulgaria',
'Charlie': 'Colombia',
'Dani': 'Denmark',
'Ethan': 'Estonia'}

You initialize your dict and iterator variables with descriptive names. To iterate over both lists at the same time, you zip them together. You add key-value pairs as desired. This takes 3 lines.

Using dictionary comprehension turns this into one line! ?

dict_comp = {name: country for name, country in zip(names, countries)}
>>> dict_comp
{'Adam': 'Argentina',
'Beth': 'Bulgaria',
'Charlie': 'Colombia',
'Dani': 'Denmark',
'Ethan': 'Estonia'}

Dictionary comprehensions are a bit like for loops in reverse. First, we state what we want our key-value pairs to be. Then we use the same for loop and wrap everything in curly braces.

Note that every comprehension can be written as a for loop. If you ever get results you don’t expect, try it as a for loop to see what is happening.

Here’s a common mistake

dict_comp_bad = {name: country 
                 for name in names 
                 for country in countries}
>>> dict_comp_bad
{'Adam': 'Estonia',
'Beth': 'Estonia',
'Charlie': 'Estonia',
'Dani': 'Estonia',
'Ethan': 'Estonia'}

What’s going on? Let’s write it as a for loop to see. First, we’ll write it out to make sure we are getting the same, undesired, result.

bad_dict = {}
for name in names:
    for country in countries:
        bad_dict[name] = country
>>> bad_dict
{'Adam': 'Estonia',
'Beth': 'Estonia',
'Charlie': 'Estonia',
'Dani': 'Estonia',
'Ethan': 'Estonia'}

Now we’ll use the bug-finder’s best friend: the print statement!

# Don't initialise dict to just check for loop logic
for name in names:
    for country in countries:
        print(name, country)
Adam Argentina
Adam Bulgaria
Adam Colombia
Adam Denmark
Adam Estonia
Beth Argentina
Beth Bulgaria
Beth Colombia
Ethan Colombia
Ethan Denmark
Ethan Estonia

Here we remove the dictionary to check what is actually happening in the loop. Now we see the problem! The issue is we have nested for loops. The loop says: for each name pair it with every country. Since dictionary keys can only appear, the value gets overwritten on each iteration. So each key’s value is the final one that appears in the loop – 'Estonia'.

The solution is to remove the nested for loops and use zip() instead.

Python Nested Dictionaries with Dictionary Comprehensions

nums = [0, 1, 2, 3, 4, 5]
dict_nums = {n: {'even': n % 2 == 0,
                 'square': n**2,
                 'cube': n**3,
                 'square_root': n**0.5}
             for n in nums}
# Pretty print for ease of reading
>>> pprint(dict_nums)
{0: {'cube': 0, 'even': True, 'square': 0, 'square_root': 0.0},
1: {'cube': 1, 'even': False, 'square': 1, 'square_root': 1.0},
2: {'cube': 8, 'even': True, 'square': 4, 'square_root': 1.4142135623730951},
3: {'cube': 27, 'even': False, 'square': 9, 'square_root': 1.7320508075688772},
4: {'cube': 64, 'even': True, 'square': 16, 'square_root': 2.0},
5: {'cube': 125, 'even': False, 'square': 25, 'square_root': 2.23606797749979}}

This is where comprehensions become powerful. We define a dictionary within a dictionary to create lots of information in a few lines of code. The syntax is exactly the same as above but our value is more complex than the first example.

Remember that our key value pairs must be unique and so we cannot create a dictionary like the following

>>> nums = [0, 1, 2, 3, 4, 5]
>>> wrong_dict = {'number': num, 'square': num ** 2 for num in nums}
  File "<stdin>", line 1
    wrong_dict = {'number': num, 'square': num ** 2 for num in nums}
SyntaxError: invalid syntax

We can only define one pattern for key-value pairs in a comprehension. But if you could define more, it wouldn’t be very helpful. We would overwrite our key-value pairs on each iteration as keys must be unique.

If-Elif-Else Statements

nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Just the even numbers
even_squares = {n: n ** 2 for n in nums
                if n % 2 == 0}
# Just the odd numbers
odd_squares = {n: n ** 2 for n in nums
               if n % 2 == 1}
>>> even_dict
{0: 0, 2: 4, 4: 16, 6: 36, 8: 64, 10: 100}
>>> odd_dict
{1: 1, 3: 9, 5: 25, 7: 49, 9: 81}

We can apply if conditions after the for statement. This affects all the values you are iterating over.

You can also apply them to your key and value definitions. We’ll now create different key-value pairs based on whether a number is odd or even.

# Use parenthesis to aid readability
different_vals = {n: ('even' if n % 2 == 0 else 'odd')
                  for n in range(5)}
>>> different_vals
{0: 'even', 1: 'odd', 2: 'even', 3: 'odd', 4: 'even'}

We can get really complex and use if/else statements in both the key-value definitions and after the for loop!

# Change each key using an f-string
{(f'{n}_cubed' if n % 2 == 1 else f'{n}_squared'): 
# Cube odd numbers, square even numbers
 (n ** 3 if n % 2 == 1 else n ** 2)
# The numbers 0-10 inclusive
 for n in range(11)
# If they are not multiples of 3
 if n % 3 != 0}
{'1_cubed': 1, '2_squared': 4, '4_squared': 16, '5_cubed': 125, '7_cubed': 343, '8_squared': 64, '10_squared': 100}

It is relatively simple to do this using comprehensions. Trying to do so with a for loop or dict() constructor would be much harder.

Alternative Formulations

The two statements are actually semantically identical:

dict([(i, chr(65+i)) for i in range(4)])

Is identical to:

{i : chr(65+i) for i in range(4)}


Let’s consider five examples of dictionary comprehensions to strengthen your understanding! The examples are improved and simplified versions of the code given here.

Dict Comprehension Example 1

Problem: create a dict comprehension from a list of integers.

# Example 1:
# (key, value) --> (string, int)
print({str(i):i for i in range(5)})
# {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4}

Each integer i is first converted to a string using the str() conversion function. The resulting mapping from str(i) to i is then stored in the dictionary for all integer values i in 0, 1, 2, 3, and 4.

Dict Comprehension Example 2

Problem: Given a list of fruit names as strings. Use dict comprehension to create a dictionary with the list elements as keys and their length as values.

# Example 2:
fruits = ['apple', 'mango', 'banana','cherry']
d = {fruit:len(fruit) for fruit in fruits}
# {'apple': 5, 'mango': 5, 'banana': 6, 'cherry': 6}

You iterate over each fruit in the list. Then, you map each fruit string to its length using Python’s built-in len() function that counts the number of characters in the string.

Dict Comprehension Example 3

Problem: Create a dictionary with dict comprehension with list elements as keys and their capitalized variants as values.

# Example 3:
d = {fruit:fruit.capitalize() for fruit in fruits}
# {'apple': 'Apple', 'mango': 'Mango', 'banana': 'Banana', 'cherry': 'Cherry'}

The string.capitalize() function capitalizes only the first letter of the given string.

Dict Comprehension Example 4

Problem: Use the enumerate() function on a list to create tuples (i, x) for the position i of the element x. Use dict comprehension with list elements as keys and their indices as values.

# Example 4:
d = {f:i for i,f in enumerate(fruits)}
# {'apple': 0, 'mango': 1, 'banana': 2, 'cherry': 3}

The enumerate(fruits) function returns the (index, element) pairs of the iterable fruits. You catch the former in variable i and the latter in variable f. Now, you inverse the mapping via f:i.

Dict Comprehension Example 5

Problem: Reverse the (key, value) mappings of a given dictionary.Roughly speaking, you want to obtain (value, key) mappings—although the old values must be seen as the new keys!

# Example 5:
# Original dictionary:
d = {str(i): i for i in range(5)}
# {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4}

# Reversed dictionary:
d_r = {v:k for k,v in d.items()}
# {0: '0', 1: '1', 2: '2', 3: '3', 4: '4'}

You use the dict.items() function to return the (key, value) pairs of the original dictionary d.

Let’s wrap up with an interactive code shell to try it yourself:

Exercise: Modify each dictionary comprehension statement by changing at least one thing!

External Resources

This tutorial is based on various resources and online sources.

Where to Go From Here?

Enough theory. Let’s get some practice!

Coders get paid six figures and more because they can solve problems more effectively using machine intelligence and automation.

To become more successful in coding, solve more real problems for real people. That’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?

You build high-value coding skills by working on practical coding projects!

Do you want to stop learning with toy projects and focus on practical code projects that earn you money and solve real problems for people?

🚀 If your answer is YES!, consider becoming a Python freelance developer! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.

If you just want to learn about the freelancing opportunity, feel free to watch my free webinar “How to Build Your High-Income Skill Python” and learn how I grew my coding business online and how you can, too—from the comfort of your own home.

Join the free webinar now!