Dictionaries (dicts)

Introduction

Dictionaries are a crucial data type used to store key:value pairs, which we’ll explain in a second. Dictionaries are hash maps/hash tables, which apply a hash function to the keys you insert, linking a location in code to your key. This makes dictionaries incredibly efficient and convenient for adding, removing, and searching for data at the expense of space.

The use for dictionaries (and hash maps in general) is that every key has a value attached to it. Keys must be unique, meaning you’ll have a unique identifier for every item you include, and its value adds supplementary information to that key.

Some examples where dictionaries would be used include:

  • Counting occurrences of a word (string: int)

  • Saving house addresses for a zip code (int: list of strings)

  • Tracking a list of people with certain titles (string: list of strings)

There will inevitably be a point where knowing how to use a dictionary will save you a lot of trouble.


Declaration

Dictionaries can be declared using {} or the dict() keyword, much like other array-like objects in Python.

dict_01 = {}  # an empty dictionary
dict_02 = dict()  # two empty dictionaries!

print(type(dict_01))
print(type(dict_02))
<class 'dict'>
<class 'dict'>

Declaring empty data structures is only so useful, so let’s put some data in there! The ways to insert data change depend on declaration method as you’ll see:

name_dict = {"first_names": ["John", "Jill"], "last_names": ["Smith", "Johnson", "Chen"]}
id_dict = dict(names=["John Johnson", "Jill Chen"], ids=["0045265987", "0025012478"])

print(type(name_dict))
print(type(id_dict))
<class 'dict'>
<class 'dict'>

Note that with key-value assignment, {} uses ":" between the key and value, while dict() uses "=" to assign your value to a named key.

We include dict() declaration here, but there are a few reasons why {} is better. While you can use any immutable object as a key, dict() restricts assignment to variables cast as strings (in the above example, names and ids are both cast as strings), while {} allows free declaration. Though a secondary concern, dict() also runs slower and takes up more memory than {}. Here’s an old article on the topic if you want to know more.

Be careful when declaring a dictionary using {}, as sets are also declared using {} when there are no colons to indicate key:value pairs. No ":", no dictionary!

name_set = {"John", "Jill", "Ellen"}
print(type(name_set))
<class 'set'>


Acquisition

The two primary methods of getting data from a dictionary are the get() method and the square bracket "[ ]" method:

things = {"fruits": ["apple", "orange", "pear"], "person": "John", "vegetables": ["carrots", "peas"]}

# If "person" is a key, they will function the same way
print(things["person"])
print(things.get("person"))
John
John
# If the key does not exist, like below, they will not
# function the same way.
print(my_dict.get("height")) # Returns None when key doesn't exist
print(my_dict["height"]) # Throws a KeyError exception because the key "height" doesn't exist
None
<KeyError: 'height'>

Much like dict() vs {}, there are nuances that make get() better than [] in terms of value acquisition, including inherent exception handling like we demonstrated above.


Resources

There are a bunch of methods that are essential for effective dictionary manipulation — here’s a great introduction to the basic methods you’ll be using with dictionaries.

Method Description

clear()

Removes all the elements from the dictionary

copy()

Returns a copy of the dictionary

fromkeys(keys)

Returns a dictionary with the specified keys and value

get(keyname)

Returns the value of the specified key

items()

Returns a list containing a tuple for each key:value pair

keys()

Returns a list conaining the dictionary’s keys

pop(keyname)

Removes the element with the specified key

popitem()

Removes the last inserted key:value pair

setdefault(keyname, value)

If the key exists, returns the value. If the key doesn’t exist, inserts key with specified value.

update(iterable)

Iterable contains key:value pairs. If key(s) exist, updates value(s). If key(s) don’t exist, insert new key:value pair(s).

values()

Returns a list of all the values in the dictionary. Returns most recent version, even if changes are made after variable assignment.

Dictionaries, like lists, are mutable, meaning that thier value can be changed after declaration.

my_dict = {"class": "Stat 190",
           "professor": "Mark Daniel Ward",
           "time": "8:30 AM - 9:20 AM"}

# currently my_dict["time"] has "8:30 AM - 9:20 AM", however after the following line, value is changed to the new value.

my_dict["time"] = "9:30 AM - 10:20 AM"
print(my_dict)
{"class": "Stat 190",
 "professor": "Mark Daniel Ward",
 "time": "9:30 AM - 10:20 AM"}

Items stored in Dictionary are ordered by the key (as you can see in the previous example). This applies to all Python from Version 3.7 When a key-value pair is appended, where the key already exists in the variable, the value of that key will be overwritten by the value of the new key.