Discover Python, Part 7: Explore the Python type hierarchy

How to use dictionaries successfully

This article returns to the exploration of the Python type hierarchy and introduces the Python dictionary container type. Unlike the Python tuple, string, and list container types discussed in previous articles, the dictionary type is an unordered container that relies on a key-to-value mapping. As a result, items in a dictionary are accessed by a key value and not by their location within a sequence. The unique features of the dictionary type may seem unusual, but they provide a great deal of power when used properly.

Share:

Robert Brunner (rb@ncsa.uiuc.edu), Research Scientist, National Center for Supercomputing Applications

Robert BrunnerRobert J. Brunner is a research scientist at the National Center for Supercomputing Applications and an assistant professor of astronomy at the University of Illinois, Urbana-Champaign. He has published several books, as well as numerous articles and tutorials, on a range of topics.



06 December 2005

The dictionary

One of the common experiences many of us share is using a language dictionary to look up the definition of an unknown word. A language dictionary provides a standard set of information for a given word, such as python. The system works by mapping or associating the definition and other information with the actual word. You find the information of interest by using the word as a key locator. This analogy extends to the Python programming language and the special container type known as a dictionary.

A dictionary data type is common to many languages. It's sometimes known as an associative array because data is associated with a key value, or as a hash table. In Python, however, the dictionary is a first-class object, which makes it easy for even novices to quickly begin using it in their own programs. Formally, a dictionary in Python is a heterogeneous, mutable, mapping container data type.

Creating a dictionary

Previous articles in this series introduced some of the container data types in the Python programming language, including the tuple, the string, and the list (see Resources). These containers are all similar in that they're sequence-based. This means you access items from these collections by their locations within the sequence. So, given a sequence named a, you can access elements using a numerical index like a[0] or a slice like a[1:5]. The dictionary container type in Python is different from the other three container types in that it is an unordered collection. Instead of accessing items from the collection given an index number, you use a key value. This means constructing a dictionary container is a little more complicated than a tuple, string, or list because you must supply both the keys and the corresponding values, as shown in Listing 1.

Listing 1. Creating a dictionary in Python
>>> d = {0: 'zero', 1: 'one', 2 : 'two', 3 : 'three', 4 : 'four', 5: 'five'}
>>> d
{0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'}
>>> len(d)

>>> type(d)          # Base object is the dict class
<type 'dict'>
>>> d = {}           # Create an empty dictionary
>>> len(d)

>>> d = {1 : 'one'}  # Create a single item dictionary
>>> d
{1: 'one'}
>>> len(d)

>>> d = {'one' : 1}  # The key value can be non-numeric
>>> d
{'one': 1}
>>> d = {'one': [0, 1,2 , 3, 4, 5, 6, 7, 8, 9]}
>>> d
{'one': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}

As this example demonstrates, a dictionary is created in Python by using curly braces, with key-value combinations separated by the colon character. If no key-value combinations are provided, you create an empty dictionary. Using one key-value combination gives a single-item dictionary, and so on, to whatever size you desire. As is the case with any container type, you can use the built-in len method to find out how many items are in the collection.

The previous example also demonstrates another important point about dictionary containers. The key isn't restricted to being an integer; it can be any nonmutable data type, including an integer, float, tuple, or string. Because a list is mutable, it can't be used as the key in a dictionary. The values in a dictionary, however, can be any data type.

Finally, this example demonstrates that the underlying data type for a dictionary in Python is the dict object. To find out more about how to use a dictionary in Python, you can use the built-in help interpreter to learn about the dict class, as shown in Listing 2.

Listing 2. Getting help for a dictionary
>>> help(dict)on class dict in module __builtin__:
     dict(object)
|  dict() -> new empty dictionary.
|  dict(mapping) -> new dictionary initialized from a mapping object's
|      (key, value) pairs.
|  dict(seq) -> new dictionary initialized as if via:
|      d = {}
|      for k, v in seq:
|          d[k] = v
|  dict(**kwargs) -> new dictionary initialized with the name=value pairs
|      in the keyword argument list.  For example:  dict(one=1, two=2)
|  
|  Methods defined here:
|  
|  __cmp__(...)
|      x.__cmp__(y) <==> cmp(x,y)
|  
|  __contains__(...)
|      x.__contains__(y) <==> y in x
|  
|  __delitem__(...)
|      x.__delitem__(y) <==> del x[y]
...

The beginning of the discussion of the dict class provides information about the constructors available to create a dictionary directly, as opposed to using the curly braces. Given the additional data that must be supplied when creating a dictionary vs. one of the other container data types, it isn't surprising that these creation methods are slightly more complex. With practice, however, you can use them easily, as shown in Listing 3.

Listing 3. Creating a dictionary in Python, part two
>>> l = [0, 1,2 , 3, 4, 5, 6, 7, 8, 9] 
>>> d = dict(l)(most recent call last):
 File "<stdin>", line 1, in ?: can't convert dictionary 
 update sequence element #0 to a sequence
   
>>> l = [(0, 'zero'), (1, 'one'), (2, 'two'), (3, 'three')]
>>> d = dict(l)
>>> d
{0: 'zero', 1: 'one', 2: 'two', 3: 'three'}
>>> l = [[0, 'zero'], [1, 'one'], [2, 'two'], [3, 'three']]
>>> d
{0: 'zero', 1: 'one', 2: 'two', 3: 'three'}
>>> d = dict(l)
>>> d
{0: 'zero', 1: 'one', 2: 'two', 3: 'three'}
>>> d  = dict(zero=0, one=1, two=2, three=3)  
>>> d
{'zero': 0, 'three': 3, 'two': 2, 'one': 1}
>>> d = dict(0=zero, 1=one, 2=two, 3=three): keyword can't be an expression

As shown, creating a dictionary requires key values and data values. The first attempt at creating a dictionary from a list fails because there are no matching key-data value pairs. The second and third examples demonstrate how to properly create a dictionary: in the first case by using a list where each element is tuple, and in the second case by using a list where each element is another list. In either case, the inner container is used to obtain the key-to-data value mapping.

The other method for creating a dict container directly is to provide the key-to-data value mapping directly. This technique allows you to explicitly define the keys and their corresponding values. This method isn't very useful because you can do the same thing directly by using curly braces. In addition, you can't use numbers for the keys in this approach, as shown in the previous example. Doing so causes an exception to be thrown.

Accessing and modifying a dictionary

Once you've created a dictionary, you need to access the data it contains. Doing so is similar to accessing values from any Python container data type, as shown in Listing 4.

Listing 4. Accessing items from a dictionary
>>> d  = dict(zero=0, one=1, two=2, three=3)
>>> d
{'zero': 0, 'three': 3, 'two': 2, 'one': 1}
>>> d['zero']

>>> d['three']

>>> d = {0: 'zero', 1: 'one', 2 : 'two', 3 : 'three', 4 : 'four', 5: 'five'}
>>> d[0]
'zero'
>>> d[4]
'four'
>>> d[6](most recent call last):
 File "<stdin>", line 1, in ?: 6

>>> d[:-1](most recent call last):
 File "<stdin>", line 1, in ?: unhashable type

As you can see, grabbing a data value from a dictionary is nearly identical to pulling data out of any container type. You place the key value inside square brackets that follow the container name. Of course, a dictionary can have non-numeric key values, which may take some getting used to if you've never used this sort of data type before. Because the order isn't important in a dictionary (the order of data in a dictionary is arbitrary), the powerful slicing functionality that you can use with other container data types isn't available with dictionaries. Trying to use slicing or trying to access data from nonexistent keys throws exceptions, indicating the relevant error.

The dictionary container in Python is also a mutable data type, which means you can change it after it has been created. As shown in Listing 5, you can add new key-to-data value mappings, you can change existing mappings, and you can remove mappings.

Listing 5. Modifying a dictionary
>>> d = {0: 'zero', 1: 'one', 2: 'two', 3: 'three'}
>>> d[0]
'zero'
>>> d[0] = 'Zero'
>>> d
{0: 'Zero', 1: 'one', 2: 'two', 3: 'three'}
>>> d[4] = 'four'
>>> d[5] = 'five'
>>> d
{0: 'Zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'}
>>> del d[0]
>>> d
{1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'}
>>> d[0] = 'zero'
>>> d
{0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five'}

Listing 5 demonstrates several important points. First, changing a data value is simple: assign the new value to the appropriate key. Second, adding new key-to-data value mappings is also simple: assign the relevant data to the new key value. Python takes care of everything automatically. You don't need to call a special method like append. Order isn't important for a dictionary container, so this should make sense because you aren't appending a new mapping but you're adding it to the container. Finally, you delete a mapping by using the del operator along with the key that should be deleted from the container.

One thing that might seem odd in Listing 5 is that the key values appear to be in numerical order, and this order matches the order in which the mappings were inserted. Don't be misled -- this doesn't always happen. The order of mappings in a Python dictionary is arbitrary and can vary across different Python installations or even from running the same code more than once using the same Python interpreter. This fact is easily demonstrated when you begin using heterogeneous keys and data values in a dictionary, as shown in Listing 6.

Listing 6. A heterogeneous container
>>> d = {0: 'zero', 'one': 1}     
>>> d
{0: 'zero', 'one': 1}
>>> d[0]
'zero'
>>> type(d[0])
<type 'str'>
>>> d['one']

>>> type(d['one'])
<type 'int'>
>>> d['two'] = [0, 1, 2] 
>>> d
{0: 'zero', 'two': [0, 1, 2], 'one': 1}
>>> d[3] = (0, 1, 2, 3)
>>> d
{0: 'zero', 3: (0, 1, 2, 3), 'two': [0, 1, 2], 'one': 1}
>>> d[3] = 'a tuple'
>>> d
{0: 'zero', 3: 'a tuple', 'two': [0, 1, 2], 'one': 1}

As this example shows, you can have different data types for the keys and the data values in a dictionary. And you can add new types by modifying the dictionary. Finally, the order of the resulting dictionaries doesn't match the order in which data was inserted. Fundamentally, the order of the items in a dictionary is controlled by the actual implementation of the Python dictionary data type. This can easily change with a new Python interpreter, so it's important that you never rely on items being in a specific order within a dictionary.

Programming with dictionaries

As an official Python data type, dictionaries support the majority of operations you may be familiar with from other, simpler data types. There operations include the general relational operators such as <, >, and ==, as shown in Listing 7.

Listing 7. General relational operators
>>> d1 = {0: 'zero'}
>>> d2 = {'zero':0}
>>> d1 < d2
>>> d2 = d1
>>> d1 < d2
>>> d1 == d2
>>> id(d1)

>>> id(d2)

>>> d2 = d1.copy()
>>> d1 == d2
>>> id(d1)

>>> id(d2)

The previous example creates two dictionaries and uses them to test the < relational operator. Granted, you'll rarely compare two dictionaries in this manner; but if you need to do so, you can.

This example then assigns the dictionary assigned to the variable d1 to the variable d2. Note that this isn't a copy operation, as demonstrated by the fact that both d1 and d2 have the same identifier values, as returned by the built-in id() method. To make a copy of a dictionary, you can use the copy() method. You can see from the last few lines in this example that the copy will compare identically to the original dictionary, but the variable holding the dictionary has a unique identifier.

When you're using a dictionary in your Python program, you'll more likely to want to test whether a particular key or value is contained in your dictionary. As shown in Listing 8, these tests are easy to perform.

Listing 8. Conditional testing and a dictionary
>>> d = {0: 'zero', 3: 'a tuple', 'two': [0, 1, 2], 'one': 1}
>>> d.keys()
[0, 3, 'two', 'one']
>>> if 0 in d.keys():
...     print 'True'
... 
>>> if 'one' in d:
...     print 'True'
... 
>>> if 'four' in d:
...     print 'Dictionary contains four'
... elif 'two' in d:
...     print 'Dictionary contains two'
... contains two

Testing for membership in the keys or data values of a dictionary is straightforward. The dictionary container data type provides several built-in methods, including the keys() method as well as the values() method, which isn't shown. These methods return a list that contains the key or data values, respectively, within the calling dictionary.

Therefore, to determine if a value is a key within a dictionary, you use the in operator to test whether the key is in the list of key values returned by calling the keys() method. You can do a similar operation to test whether a value is in the list of data values returned by calling the values() method. However, you can use the dictionary name as a shorthand notation. This makes sense because you generally want to know whether a data value -- rather than a key value -- is in a dictionary.

In "Discover Python, Part 6," you saw how to easily step through the items in a container by iterating over the items using the for loop. The same technique works with a Python dictionary, as shown in Listing 9.

Listing 9. Iteration and a dictionary
>>> d = {0: 'zero', 3: 'a tuple', 'two': [0, 1, 2], 'one': 1}
>>> for k in d.iterkeys():
...     print d[k]
... tuple
[0, 1, 2]

>>> for v in d.itervalues():
...     print v
... tuple
[0, 1, 2]

>>> for k, v in d.iteritems():
...     print 'd[',k,'] = ',v
... [ 0 ] =  zero[ 3 ] =  a tuple[ two ] =  [0, 1, 2][ one ] =  1

This example demonstrates three means for iterating through a dictionary: by using the Python iterator returned from the iterkeys(), itervalues(), or iteritems() methods. (As an aside, you can verify that these methods return an iterator and not a container data type by calling the appropriate method on a dictionary directly, as in d.iterkeys().) The iterkeys() method lets you iterate through the key values of a dictionary, whereas the itervalues() method allows you to iterate through the data values contained within a dictionary. On the other hand, the iteritems() method lets you iterate through the key-to-data value mappings at the same time.


The dictionary: Another powerful Python container

This article has discussed the Python dictionary data type. The dictionary is a heterogeneous, mutable container that relies on a key-to-data value mapping, rather than a particular numerical order to access items from the container. Accessing, adding items to, and deleting items from a dictionary are all simple operations, and dictionaries can be easily incorporated into compound statements like an if statement or a for loop. You can store all different types of data in a dictionary, and this data can be accessed by name or other compound key values (such as a tuple), so Python dictionaries let you write succinct yet powerful programming statements.

Resources

Learn

  • Find all of the articles in the developerWorks "Discover Python" series.
  • When you have a working Python interpreter, the Python tutorial is a great place to start learning the language.
  • Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=99820
ArticleTitle=Discover Python, Part 7: Explore the Python type hierarchy
publish-date=12062005