Dictionaries in Python

You can define a dictionary by enclosing a comma-separated list of key-value pairs in curly braces ({}).

A colon (:) separates each key from its associated value:

In [ ]:
new_dict = {
    <key>: <value>,
    <key>: <value>,
      .
      .
      .
    <key>: <value>
}

The following defines a dictionary that maps countries to their capitals.

In [1]:
world_map = {
    'Italy': 'Rome',
    'Japan': 'Tokio',
    'Canada': 'Ottawa',
    'Bolivia': 'La Paz',
    'Egypt': 'Cairo'
}

You can also construct a dictionary with the built-in dict() function. The argument to dict() should be a sequence of key-value pairs. A list of tuples works well for this...

In [ ]:
new_dict = dict([
    (<key>,<value>),
    (<key>,<value>),
      .
      .
      .
    (<key>,<value>)
])

world_map dictionary can then also be defined this way:

In [2]:
world_map = dict([
    ('Italy', 'Rome'),
    ('Japan', 'Tokio'),
    ('Canada', 'Ottawa'),
    ('Bolivia', 'La Paz'),
    ('Egypt', 'Cairo')
])

If the key values are simple strings, they can be specified as keyword arguments. So here is another way to define world_map dict.

In [3]:
world_map = dict(
    Italy='Rome',
    Japan='Tokio',
    Canada='Ottawa',
    Bolivia='La Paz',
    Egypt='Cairo'
)

Once you’ve defined a dictionary, you can display its contents, the same as you can do for a list.

In [4]:
type(world_map)
Out[4]:
dict
In [5]:
world_map
Out[5]:
{'Italy': 'Rome',
 'Japan': 'Tokio',
 'Canada': 'Ottawa',
 'Bolivia': 'La Paz',
 'Egypt': 'Cairo'}

As we see above, the entries in the dictionary appear in the order they were defined. But the order is not guaranteed when we retrieve these elements from the dictionary.

Accessing Python Dictionary Values

A value is retrieved from a dictionary by specifying its corresponding key in square brackets ([]) as shown below.

In [7]:
world_map['Canada']
Out[7]:
'Ottawa'
In [8]:
world_map['Italy']
Out[8]:
'Rome'

If you refer to a key that is not in the dictionary, Python raises an exception:

In [9]:
world_map['Spain']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-9-1b16fe0807de> in <module>
----> 1 world_map['Spain']

KeyError: 'Spain'

Also dictionary elements can not be accessed by numerical index.

In [6]:
world_map[1]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-6-5591c2a47ef9> in <module>
----> 1 world_map[1]

KeyError: 1

Adding an entry to an existing dictionary is simply a matter of assigning a new key and value:

In [10]:
world_map['South Africa'] = 'Pretoria'
In [11]:
world_map
Out[11]:
{'Italy': 'Rome',
 'Japan': 'Tokio',
 'Canada': 'Ottawa',
 'Bolivia': 'La Paz',
 'Egypt': 'Cairo',
 'South Africa': 'Pretoria'}

Python Update Dictionary

If you want to update an entry, you can just assign a new value to an existing key:

In [12]:
world_map['Bolivia'] = 'Sucre'
In [13]:
world_map
Out[13]:
{'Italy': 'Rome',
 'Japan': 'Tokio',
 'Canada': 'Ottawa',
 'Bolivia': 'Sucre',
 'Egypt': 'Cairo',
 'South Africa': 'Pretoria'}

Python Remove Entry in Dictionary

To delete an entry, use the del statement as shown below.

In [14]:
del world_map['Egypt']
In [15]:
world_map
Out[15]:
{'Italy': 'Rome',
 'Japan': 'Tokio',
 'Canada': 'Ottawa',
 'Bolivia': 'Sucre',
 'South Africa': 'Pretoria'}

Dictionary Keys vs List Indices

Note in the above snippets that Dictionary raises the same exception "KeyError" when a dictionary is accessed with either an undefined key or by a numeric index.

In [16]:
world_map['France']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-16-d3401b0d43ef> in <module>
----> 1 world_map['France']

KeyError: 'France'
In [17]:
world_map[1]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-17-5591c2a47ef9> in <module>
----> 1 world_map[1]

KeyError: 1

Note that both of the above errors are same. In both cases, it is "KeyError". [1] is not index but it is a key.

Look at below example where I am using integers as keys in Python dictionaries.

In [18]:
fruits = { 
    0: 'apple', 
    1: 'banana', 
    2: 'lemon',
    3: 'pear',
    4: 'watermelon'
}
In [19]:
fruits[0]
Out[19]:
'apple'
In [20]:
fruits[3]
Out[20]:
'pear'

In the expressions world_map[1], fruits[0], and fruits[2], the numbers in square brackets are keys not indices. Also since these are keys, the order of items in the dictionary is not maintained. If we change the order of these keys, let us say in reverse order, you would still get the same values using the same keys:

In [21]:
fruits = {
    4: 'watermelon',
    3: 'pear',
    2: 'lemon',
    1: 'banana',
    0: 'apple'
}
In [22]:
fruits[0]
Out[22]:
'apple'
In [23]:
fruits[3]
Out[23]:
'pear'

The syntax may look similar, but you can’t treat a dictionary like a list:

In [24]:
type(fruits)
Out[24]:
dict
In [25]:
fruits[-1]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-25-63d1de4da62e> in <module>
----> 1 fruits[-1]

KeyError: -1
In [26]:
fruits[1:3]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-26-54a863e6532a> in <module>
----> 1 fruits[1:3]

TypeError: unhashable type: 'slice'
In [27]:
fruits.append('pineapple')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-27-40977409ea20> in <module>
----> 1 fruits.append('pineapple')

AttributeError: 'dict' object has no attribute 'append'

Building a Python Dictionary Incrementally

In many cases, we dont know the content of Python dictionaries in advance and need to fill up the key,values as the need arises. For that we need to first define a empty dictionary and then you can add new keys and values one at a time. Let us go through an example to illusterate that.

In [28]:
restaurant = {}
In [29]:
type(restaurant)
Out[29]:
dict
In [30]:
restaurant['name'] = 'Delicious Food Restaurant'
In [31]:
restaurant['category'] = 'fast food'
In [32]:
restaurant['menu'] = ['pizza', 'french fries', 'sandwich', 'donuts']
In [33]:
restaurant['workers'] = 8
In [34]:
restaurant['address'] = {
    'street': '1800 Lincoln Avenue',
    'city': 'San Francisco',
    'state': 'California'
}
In [35]:
restaurant
Out[35]:
{'name': 'Delicious Food Restaurant',
 'category': 'fast food',
 'menu': ['pizza', 'french fries', 'sandwich', 'donuts'],
 'workers': 8,
 'address': {'street': '1800 Lincoln Avenue',
  'city': 'San Francisco',
  'state': 'California'}}
In [36]:
restaurant['name']
Out[36]:
'Delicious Food Restaurant'
In [37]:
restaurant['menu']
Out[37]:
['pizza', 'french fries', 'sandwich', 'donuts']
In [38]:
restaurant['workers']
Out[38]:
8

Retrieving the values in the sublist or subdictionary requires an additional index or key:

In [39]:
restaurant['menu'][2]
Out[39]:
'sandwich'
In [40]:
restaurant['menu'][-1]
Out[40]:
'donuts'

Python Dictionary with Different Key Types

Python dictionaries are very robust, they can be of any type.

In restaurant dict, some of the values are strings, one is an integer, one is a list, and one is another dictionary.

In [41]:
new_dict = {
    3.14: 'This is a float key',
    88: 'This is an integer key',
    True: 'This is a bool key'
}
In [42]:
new_dict[True]
Out[42]:
'This is a bool key'
In [43]:
new_dict[3.14]
Out[43]:
'This is a float key'
In [44]:
new_dict[88]
Out[44]:
'This is an integer key'

Note in below example, our keys are of type integer, float, and Boolean.

In [45]:
new_dict = {
    3.14: 'This is a float key',
    88: 'This is an integer key',
    True: 'This is a bool key'
}

new_dict
Out[45]:
{3.14: 'This is a float key',
 88: 'This is an integer key',
 True: 'This is a bool key'}

You can even use built-in Python objects like types and functions.

In [46]:
obj_dict = { int: 45, float: 2.7183, bool: True }
In [47]:
obj_dict[float]
Out[47]:
2.7183
In [48]:
obj_dict[bool]
Out[48]:
True
In [49]:
obj_dict = { bin: 0, hex: 1, oct: 2}
In [50]:
obj_dict[bin]
Out[50]:
0
In [51]:
obj_dict[oct]
Out[51]:
2

Duplicate Keys in Python Dictionary

However, there are couple of things to watch for when we are dealing with Python dictionaries. Python dictionaries don't allow duplicate dictionaries. Every key in Python dictionary has a value. If we try to enter the same key in Python dictionary, the key value is overwritten. Let us show this with an example.

In [52]:
world_map = {
    'Italy': 'Rome',
    'Japan': 'Tokio',
    'Canada': 'Ottawa',
    'Bolivia': 'La Paz',
    'Egypt': 'Cairo',
    'Nigeria': 'Lagos'
}
In [53]:
world_map['Nigeria'] = 'Abuja'
world_map
Out[53]:
{'Italy': 'Rome',
 'Japan': 'Tokio',
 'Canada': 'Ottawa',
 'Bolivia': 'La Paz',
 'Egypt': 'Cairo',
 'Nigeria': 'Abuja'}

Also if you define the same key again while defining a Python dictionary. Dictionary key's value is overwritten by the latter. Checkout following code to learn this concept.

In [54]:
world_map = {
    'Italy': 'Rome',
    'Japan': 'Tokio',
    'Nigeria': 'Lagos',
    'Canada': 'Ottawa',
    'Bolivia': 'La Paz',
    'Egypt': 'Cairo',
    'Nigeria': 'Abuja'
}
In [55]:
world_map
Out[55]:
{'Italy': 'Rome',
 'Japan': 'Tokio',
 'Nigeria': 'Abuja',
 'Canada': 'Ottawa',
 'Bolivia': 'La Paz',
 'Egypt': 'Cairo'}

Note in the above example, 'Nigeria' key's value is 'Abuja' not 'Lagos'.

Tuple as Python Dictionary Keys

A tuple can also be a dictionary key, because tuples are immutable:

In [56]:
food_inventory = {
    (1, 1): 'eggs',
    (1, 2): 'butter',
    (2, 1): 'cheese',
    (2, 2): 'bacon',
    (3, 1): 'milk',
    (3, 2): 'juice',
    (3, 3): 'yogurt'
}
In [57]:
food_inventory[(1, 1)]
Out[57]:
'eggs'
In [58]:
food_inventory[(2, 1)]
Out[58]:
'cheese'
In [59]:
food_inventory[(3, 2)]
Out[59]:
'juice'

However, neither a list nor another dictionary can serve as a dictionary key, because lists and dictionaries are mutable:

In [60]:
food_inventory = {
    [1,1]: 'eggs',
    [1,2]: 'butter',
    [2,1]: 'cheese',
    [2,2]: 'bacon',
    [3,1]: 'milk',
    [3,2]: 'juice',
    [3,3]: 'yogurt'
}
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-60-1e8e435fa9f7> in <module>
      6     [3,1]: 'milk',
      7     [3,2]: 'juice',
----> 8     [3,3]: 'yogurt'
      9 }

TypeError: unhashable type: 'list'

Note: Why does the above error message say unhashable

Python keys should be hashable that means Python should be able to generate a fixed unique value using its built-in hash() function. If the key is not hashable, then Python throws an exception.

In [61]:
hash('hashed string')
Out[61]:
2254601932621853240
In [62]:
hash(['hashed','string'])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-62-252e97405187> in <module>
----> 1 hash(['hashed','string'])

TypeError: unhashable type: 'list'

Restrictions on Dictionary Values

On the contrary, there are no restrictions on Python dictionary values. Dictionary values can be of any type and can have duplicate values. Let us understand using an example.

In [63]:
app = {
    'Twitter': 'social media network',
    'YouTube': 'social media network',
    'Instagram': 'social media network'
}  
In [64]:
app
Out[64]:
{'Twitter': 'social media network',
 'YouTube': 'social media network',
 'Instagram': 'social media network'}

Below code checks if the key values are same.

In [65]:
app['Twitter'] == app['YouTube'] == app['Instagram']
Out[65]:
True

Operators and Built-in Functions

For example, the "in" and "not in" operators return True or False according to whether the specified operand occurs as a key in the dictionary.

In [66]:
world_map = {
    'Norway': 'Oslo',
    'India': 'New Delhi',
    'Mexico': 'Mexico City',
    'Venezuela': 'Caracas',
    'Ghana': 'Accra'
}
In [67]:
'Norway' in world_map
Out[67]:
True
In [68]:
'China' in world_map
Out[68]:
False
In [69]:
'China' not in world_map
Out[69]:
True

You can use the "in" operator to avoid raising an error when trying to access a key that is not in the dictionary.

In [70]:
world_map['Spain']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-70-1b16fe0807de> in <module>
----> 1 world_map['Spain']

KeyError: 'Spain'
In [71]:
'Spain' in world_map and world_map['Spain']
Out[71]:
False

The len() function returns the number of key-value pairs in a dictionary.

In [72]:
world_map = {
    'Norway': 'Oslo',
    'India': 'New Delhi',
    'Mexico': 'Mexico City',
    'Venezuela': 'Caracas',
    'Ghana': 'Accra'
}
In [73]:
len(world_map)
Out[73]:
5

Built-in Dictionary Methods

There are many Python built-in dictioary methods available. In this section, we will go over the following methods.

  • dict.clear()
  • dict.get()
  • dict.items()
  • dict.keys()
  • dict.values()
  • dict.pop()
  • dict.popitem()
  • dict.update()

dict.clear()

clear() empties dictionary of all key-value pairs.

In [74]:
solar_system = {'Mars': 4, 'Venus': 2, 'Earth': 3}
In [75]:
solar_system
Out[75]:
{'Mars': 4, 'Venus': 2, 'Earth': 3}
In [76]:
solar_system.clear()
In [77]:
solar_system
Out[77]:
{}

dict.get()

get() searches dictionary for 'key' and returns the associated value if it is found. If 'key' is not found, it returns None.

In [78]:
solar_system = {'Mars': 4, 'Venus': 2, 'Earth': 3}
In [79]:
position = solar_system.get('Earth')
print(position)
3
In [80]:
position = solar_system.get('Saturn')
print(position)
None

If 'key' is not found and the optional 'default' argument is specified, then default value is returned instead of None as shown below.

In [81]:
position = solar_system.get('Pluto', 'This planet was not found')
print(position)
This planet was not found
In [82]:
position = solar_system.get('Pluto', -1)
print(position)
-1

dict.items()

items() returns a list of tuples containing the key-value pairs. The first item in each tuple is the key, and the second item is the key’s value:

In [83]:
solar_system = {'Mars': 4, 'Venus': 2, 'Earth': 3}
solar_system
Out[83]:
{'Mars': 4, 'Venus': 2, 'Earth': 3}
In [84]:
list(solar_system.items())
Out[84]:
[('Mars', 4), ('Venus', 2), ('Earth', 3)]
In [85]:
list(solar_system.items())[1][0]
Out[85]:
'Venus'
In [86]:
list(solar_system.items())[1][1]
Out[86]:
2

dict.keys()

keys() returns a list of all keys.

In [87]:
solar_system = {'Mars': 4, 'Venus': 2, 'Earth': 3}
solar_system
Out[87]:
{'Mars': 4, 'Venus': 2, 'Earth': 3}
In [88]:
list(solar_system.keys())
Out[88]:
['Mars', 'Venus', 'Earth']

dict.values()

values() returns a list of all values.

In [89]:
solar_system = {'Mars': 4, 'Venus': 2, 'Earth': 3}
solar_system
Out[89]:
{'Mars': 4, 'Venus': 2, 'Earth': 3}
In [90]:
list(solar_system.values())
Out[90]:
[4, 2, 3]

dict.pop()

If 'key' is present in dictionary, pop('key') removes 'key' and returns its associated value.

In [91]:
solar_system = {'Mars': 4, 'Venus': 2, 'Earth': 3}
solar_system
Out[91]:
{'Mars': 4, 'Venus': 2, 'Earth': 3}
In [92]:
solar_system.pop('Mars')
Out[92]:
4
In [93]:
solar_system
Out[93]:
{'Venus': 2, 'Earth': 3}

pop('key') raises a KeyError exception if 'key' is not in dictionary:

In [94]:
solar_system = {'Mars': 4, 'Venus': 2, 'Earth': 3}
In [95]:
solar_system.pop('Neptune')
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-95-d6d521474d12> in <module>
----> 1 solar_system.pop('Neptune')

KeyError: 'Neptune'

If 'key' is not in dictionary, and the optional 'default' argument is specified, then default value is returned, and no exception is raised.

In [96]:
solar_system = {'Mars': 4, 'Venus': 2, 'Earth': 3}
In [97]:
solar_system.pop('Neptune', -1)
Out[97]:
-1
In [98]:
solar_system.pop('Neptune', 'This planet was not found')
Out[98]:
'This planet was not found'
In [99]:
solar_system
Out[99]:
{'Mars': 4, 'Venus': 2, 'Earth': 3}

dict.popitem()

popitem() removes the last key-value pair added to dictionary and returns it as a tuple.

In [100]:
solar_system = {'Mars': 4, 'Venus': 2, 'Earth': 3}
In [101]:
solar_system.popitem()
Out[101]:
('Earth', 3)
In [102]:
solar_system
Out[102]:
{'Mars': 4, 'Venus': 2}
In [103]:
solar_system.popitem()
Out[103]:
('Venus', 2)
In [104]:
solar_system
Out[104]:
{'Mars': 4}

If dictionary is empty, popitem() raises a KeyError exception

In [105]:
solar_system = {}
In [106]:
solar_system.popitem()
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-106-1582d224425a> in <module>
----> 1 solar_system.popitem()

KeyError: 'popitem(): dictionary is empty'

dict.update()

In [107]:
solar_system = {'Mars': 4, 'Venus': 2, 'Earth': 3, 'Pluto': 9}
new_solar_system = {'Pluto': -1, 'Mercury': 1, 'Jupiter': 5}
In [108]:
solar_system.update(new_solar_system)
solar_system
Out[108]:
{'Mars': 4, 'Venus': 2, 'Earth': 3, 'Pluto': -1, 'Mercury': 1, 'Jupiter': 5}

'obj' can be sequence of key-value pairs or can be list of tuples.

In [109]:
solar_system = {'Mars': 4, 'Venus': 2, 'Earth': 3, 'Pluto': 9}
In [110]:
solar_system.update([('Jupiter', 5), ('Pluto', -1)])
solar_system
Out[110]:
{'Mars': 4, 'Venus': 2, 'Earth': 3, 'Pluto': -1, 'Jupiter': 5}