Chapter 6. Lists and Dictionaries

This chapter presents the list and dictionary object types—collections of other objects, which are the main workhorses in almost all Python scripts. As we’ll see, both of these types are remarkably flexible: they can be changed, can grow and shrink on demand, and may contain and be nested in any other kind of object. By leveraging these types, we can build up and process arbitrarily rich information structures in our scripts.

Lists

The next stop on the built-in object tour is the Python list. Lists are Python’s most flexible ordered collection object type. Unlike strings, lists can contain any sort of object: numbers, strings, even other lists. Python lists do the work of most of the collection data structures you might have to implement manually in lower-level languages such as C. In terms of some of their main properties, Python lists are:

Ordered collections of arbitrary objects

From a functional view, lists are just a place to collect other objects, so you can treat them as a group. Lists also define a left-to-right positional ordering of the items in the list.

Accessed by offset

Just as with strings, you can fetch a component object out of a list by indexing the list on the object’s offset. Since items in lists are ordered by their positions, you can also do such tasks as slicing and concatenation.

Variable length, heterogeneous, arbitrarily nestable

Unlike strings, lists can grow and shrink in place (they can have variable length), and may contain any sort of object, not just one-character strings (they’re heterogeneous). Because lists can contain other complex objects, lists also support arbitrary nesting; you can create lists of lists of lists.

Of the category mutable sequence

In terms of our type category qualifiers, lists can be both changed in place (they’re mutable) and respond to all the sequence operations used with strings like indexing, slicing, and concatenation. In fact, sequence operations work the same on lists. Because lists are mutable, they also support other operations strings don’t, such as deletion and index assignment.

Arrays of object references

Technically, Python lists contain zero or more references to other objects. Lists might remind you of arrays of pointers (addresses). Fetching an item from a Python list is about as fast as indexing a C array; in fact, lists really are C arrays inside the Python interpreter. Python always follows a reference to an object whenever the reference is used, so your program only deals with objects. Whenever you insert an object into a data structure or variable name, Python always stores a reference to the object, not a copy of it (unless you request a copy explicitly).

Table 6-1 summarizes common list object operations.

Table 6-1. Common list literals and operations

Operation

Interpretation

L1 = [ ]

An empty list

L2 = [0, 1, 2, 3]

Four items: indexes 0..3

L3 = ['abc', ['def', 'ghi']]

Nested sublists

L2[i] L3[i][j]L2[i:j] len(L2)

Index, slice, length

L1 + L2L2 * 3

Concatenate, repeat

for x in L2 3 in L2

Iteration, membership

L2.append(4) L2.extend([5,6,7])L2.sort( )L2.index(1) L2.reverse( )

Methods: grow, sort, search, reverse, etc.

del L2[k]del L2[i:j]L2.pop( )L2[i:j] = [ ]

Shrinking

L2[i] = 1L2[i:j] = [4,5,6]

Index assignment, slice assignment

range(4)xrange(0, 4)

Make lists/tuples of integers

L4 = [x**2 for x in range(5)]

List comprehensions (Chapter 14)

When written down, lists are coded as a series of objects (or expressions that return objects) in square brackets, separated by commas. For instance, the second row in Table 6-1 assigns variable L2 to a four-item list. Nested lists are coded as a nested square-bracketed series (row 3), and the empty list is just a square-bracket pair with nothing inside (row 1).[1]

Many of the operations in Table 6-1 should look familiar, since they are the same sequence operations put to work on strings—indexing, concatenation, iteration, and so on. Lists also respond to list-specific method calls (which provide utilities such as sorting, reversing, adding items on the end, etc.), as well as in-place change operations (deleting items, assignment to indexes and slices, and so forth). Lists get the tools for change operations because they are a mutable object type.

Lists in Action

Perhaps the best way to understand lists is to see them at work. Let’s once again turn to some simple interpreter interactions to illustrate the operations in Table 6-1.

Basic List Operations

Lists respond to the + and * operators much like strings; they mean concatenation and repetition here too, except that the result is a new list, not a string. In fact, lists respond to all of the general sequence operations used for strings.

% python
>>> len([1, 2, 3])                    # Length
3
>>> [1, 2, 3] + [4, 5, 6]             # Concatenation
[1, 2, 3, 4, 5, 6]
>>> ['Ni!'] * 4                       # Repetition
['Ni!', 'Ni!', 'Ni!', 'Ni!']
>>> 3 in [1, 2, 3]                    # Membership (1 means true)
1
>>> for x in [1, 2, 3]: print x,      # Iteration
...
1 2 3

We talk more about for iteration and the range built-ins in Chapter 10, because they are related to statement syntax; in short, for loops step through items in a sequence. The last entry in Table 6-1, list comprehensions, are covered in Chapter 14; they are a way to build lists by applying expressions to sequences, in a single step.

Although + works the same for lists and strings, it’s important to know that it expects the same sort of sequence on both sides—otherwise you get a type error when the code runs. For instance, you cannot concatenate a list and a string, unless you first convert the list to a string using backquotes, str, or % formatting. You could also convert the string to a list; the list built-in function does the trick:

>>> `[1, 2]` + "34"         # Same as "[1, 2]" + "34"
'[1, 2]34'
>>> [1, 2] + list("34")     # Same as [1, 2] + ["3", "4"]
[1, 2, '3', '4']

In dexing, Slicing, and Matrixes

Because lists are sequences, indexing and slicing work the same way, but the result of indexing a list is whatever type of object lives at the offset you specify, and slicing a list always returns a new list:

>>> L = ['spam', 'Spam', 'SPAM!']
>>> L[2]                               # Offsets start at zero.
'SPAM!'
>>> L[-2]                              # Negative: count from the right.
'Spam'
>>> L[1:]                              # Slicing fetches sections.
['Spam', 'SPAM!']

One note here: because you can nest lists (and other types) with lists, you will sometimes need to string together index operations to go deeper into a data structure. For example, one of the simplest ways to represent matrixes (multidimensional arrays) in Python, is as lists with nested sublists. Here’s a basic, list-based, 3-by-3, two-dimensional array:

>>> matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

With one index, you get an entire row (really, a nested sublist); with two, you get a item within the row:

>>> matrix[1]
[4, 5, 6]
>>> matrix[1][1]
5
>>> matrix[2][0]
7 
>>> matrix = [[1, 2, 3],
...           [4, 5, 6],
...           [7, 8, 9]]
>>> matrix[1][1]
5

Notice the last portion of this example; lists can naturally span multiple lines if you want them to. Later in this chapter, you’ll also see a dictionary-based matrix representation. The NumPy extension mentioned earlier provides other ways to handle matrixes.

Changing Lists in-Place

Because lists are mutable, they support operations that change a list object in-place; that is, the operations in this section all modify the list object directly, without forcing you to make a new copy as you had to for strings. But since Python only deals in object references, the distinction between in-place changes and new objects does matter; if you change an object in place, you might impact more than one reference to it at the same time.

Index and slice assignment

When using a list, you can change its contents by assigning to a particular item (offset), or an entire section (slice):

>>> L = ['spam', 'Spam', 'SPAM!']
>>> L[1] = 'eggs'                  # Index assignment
>>> L
['spam', 'eggs', 'SPAM!']
>>> L[0:2] = ['eat', 'more']       # Slice assignment: delete+insert
>>> L                              # Replaces items 0,1
['eat', 'more', 'SPAM!']

Both index and slice assignments are in-place changes—they modify the subject list directly, rather than generating a new list object for the result. Index assignment works much as it does in C, and most other languages: Python replaces the object reference at the designated offset with a new one.

Slice assignment, the last operation in the preceding example, replaces an entire section of a list in a single step. Because it can be a bit complex, it is perhaps best thought of as the combination of two steps:

  1. Deletion. The slice you specify on the left of the = is deleted.

  2. Insertion. The new items on the right are inserted into the list on the left, at the place where the old slice was deleted.

This isn’t what really happens,[2] but it tends to help clarify why the number of items inserted doesn’t have to match the number of items deleted. For instance, given a list L that has the value [1,2,3], the assignment L[1:2]=[4,5] sets L to the list [1,4,5,3]. Python first deletes the 2 (a one-item slice), then inserts items 4 and 5 where the deleted 2 used to be. It also explains why L[1:2]=[ ] is really a deletion operation.

List method calls

Like strings, Python list objects also support type-specific method calls:

>>> L.append('please')                # Append method call.
>>> L
['eat', 'more', 'SPAM!', 'please']
>>> L.sort(  )                          # Sort list items ('S' < 'e').
>>> L
['SPAM!', 'eat', 'more', 'please']

Methods were introduced in Chapter 5. In brief, they are functions (or attributes that reference functions) that are associated with a particular object. Methods provide type-specific tools; the list methods presented here, for instance, are only available for lists.

The list append method simply tacks a single item (object reference) onto the end of the list. Unlike concatenation, append expects you to pass in a single object, not a list. The effect of L.append(X) is similar to L+[X], but the former changes L in place, and the latter makes a new list.[3] The sort method orders a list in-place; by default, it uses Python standard comparison tests (here, string comparisons), and sorts in ascending fashion. You can also pass in a comparison function of your own to sort.

(Beware that append and sort change the associated list object in-place, but don’t return the list as a result (technically, they both return a value called None). If you say something like L=L.append(X), you won’t get the modified value of L (in fact, you’ll lose the reference to the list altogether); when you use attributes such as append and sort, objects are changed as a side effect, so there’s no reason to reassign.)

As for strings, other list methods perform other specialized operations. For instance, reverse reverses the list in-place, and the extend and pop methods insert multiple items at the end, and delete an item from the end, respectively:

>>> L = [1, 2]
>>> L.extend([3,4,5])      # Append multiple items.
>>> L
[1, 2, 3, 4, 5]
>>> L.pop(  )                # Delete, return last item.
5
>>> L
[1, 2, 3, 4]
>>> L.reverse(  )            # In-place reversal.
>>> L
[4, 3, 2, 1]

In some types of programs, the list pop method used here is often used in conjuction with append to implement a quick last-in-first-out stack structure. The end of the list serves as the top of the stack:

>>> L = [  ]
>>> L.append(1)                    # Push onto stack.
>>> L.append(2)
>>> L
[1, 2]
>>> L.pop(  )                        # Pop off stack.
2
>>> L
[1]

Finally, because lists are mutable, you can also use the del statement to delete an item or section:

>>> L
['SPAM!', 'eat', 'more', 'please']
>>> del L[0]                       # Delete one item.
>>> L
['eat', 'more', 'please']
>>> del L[1:]                      # Delete an entire section.
>>> L                              # Same as L[1:] = [  ]
['eat']

Since slice assignment is a deletion plus an insert, you can also delete sections of lists by assigning an empty list to a slice (L[i:j]=[ ]); Python deletes the slice named on the left and then inserts nothing. Assigning an empty list to an index, on the other hand, just stores a reference to the empty list in the specified slot, rather than deleting it:

>>> L = ['Already', 'got', 'one']
>>> L[1:] = [  ]
>>> L
['Already']
>>> L[0] = [  ]
>>> L
[[  ]]

Here are a few pointers before moving on. Although all the operations above are typical, there are additional list methods and operations not illustrated here (including methods for inserting and searching). For a comprehensive and up-to-date list of type tools, you should always consult Python’s manuals, or the Python Pocket Reference (O’Reilly) and other reference texts described in Preface.

We’d also like to remind you one more time that all the in-place change operations above work only for mutable objects: they won’t work on strings (or tuples, discussed ahead), no matter how hard you try.

Dictionaries

Besides lists, dictionaries are perhaps the most flexible built-in data type in Python. If you think of lists as ordered collections of objects, dictionaries are unordered collections; their chief distinction is that items are stored and fetched in dictionaries by key, instead of positional offset.

Being a built-in type, dictionaries can replace many of the searching algorithms and data structures you might have to implement manually in lower-level languages—indexing a dictionary is a very fast search operation. Dictionaries also sometimes do the work of records and symbol tables used in other languages, can represent sparse (mostly empty) data structures, and much more. In terms of their main properties, dictionaries are:

Accessed by key, not offset

Dictionaries are sometimes called associative arrays or hashes. They associate a set of values with keys, so that you can fetch an item out of a dictionary using the key that stores it. You use the same indexing operation to get components in a dictionary, but the index takes the form of a key, not a relative offset.

Unordered collections of arbitrary objects

Unlike lists, items stored in a dictionary aren’t kept in any particular order; in fact, Python randomizes their order in order to provide quick lookup. Keys provide the symbolic (not physical) location of items in a dictionary.

Variable length, heterogeneous, arbitrarily nestable

Like lists, dictionaries can grow and shrink in place (without making a copy), they can contain objects of any type, and support nesting to any depth (they can contain lists, other dictionaries, and so on).

Of the category mutable mapping

Dictionaries can be changed in place by assigning to indexes, but don’t support the sequence operations that work on strings and lists. Because dictionaries are unordered collections, operations that depend on a fixed order (e.g., concatenation, slicing) don’t make sense. Instead, dictionaries are the only built-in representative of the mapping type category—objects that map keys to values.

Tables of object references (hash tables)

If lists are arrays of object references, dictionaries are unordered tables of object references. Internally, dictionaries are implemented as hash tables (data structures that support very fast retrieval), which start small and grow on demand. Moreover, Python employs optimized hashing algorithms to find keys, so retrieval is very fast. Dictionaries store object references (not copies), just like lists.

Table 6-2 summarizes some of the most common dictionary operations (see the library manual for a complete list). Dictionaries are written as a series of key:value pairs, separated by commas, and enclosed in curly braces.[4] An empty dictionary is an empty set of braces, and dictionaries can be nested by writing one as a value inside another dictionary, or within a list or tuple.

Table 6-2. Common dictionary literals and operations

Operation

Interpretation

D1 = { }

Empty dictionary

D2 = {'spam': 2, 'eggs': 3}

Two-item dictionary

D3 = {'food': {'ham': 1, 'egg': 2}}

Nesting

D2['eggs']d3['food']['ham']

Indexing by key

D2.has_key('eggs'), 'eggs' in D2D2.keys( )D2.values( )D2.copy( )D2.get(key, default)D2.update(D1)

Methods: membership test, keys list, values list, copies, defaults, merge, etc.

len(d1)

Length (number stored entries)

D2[key] = 42del d2[key]

Adding/changing, deleting

D4 = dict(zip(keyslist, valslist))

Construction (Chapter 10)

Dictionaries in Action

As Table 6-2 suggests, dictionaries are indexed by key, and nested dictionary entries are referenced by a series of indexes (keys in square brackets). When Python creates a dictionary, it stores its items in any order it chooses; to fetch a value back, supply the key that it is associated with. Let’s go back to the interpreter to get a feel for some of the dictionary operations in Table 6-2.

Basic Dictionary Operations

In normal operation, you create dictionaries and store and access items by key:

% python
>>> d2 = {'spam': 2, 'ham': 1, 'eggs': 3}    # Make a dictionary.
>>> d2['spam']                               # Fetch value by key.
2
>>> d2                                       # Order is scrambled.
{'eggs': 3, 'ham': 1, 'spam': 2}

Here, the dictionary is assigned to variable d2; the value of the key 'spam' is the integer 2. We use the same square bracket syntax to index dictionaries by key as we did to index lists by offsets, but here it means access by key, not position.

Notice the end of this example: the order of keys in a dictionary will almost always be different than what you originally typed. This is on purpose—to implement fast key lookup (a.k.a. hashing), keys need to be randomized in memory. That’s why operations that assume a left-to-right order do not apply to dictionaries (e.g., slicing, concatenation); you can only fetch values by key, not position.

The built-in len function works on dictionaries too; it returns the number of items stored away in the dictionary, or equivalently, the length of its keys list. The dictionary has_key method allows you to test for key existence, and the keys method returns all the keys in the dictionary, collected in a list. The latter of these can be useful for processing dictionaries sequentially, but you shouldn’t depend on the order of the keys list. Because the keys result is a normal list, however, it can always be sorted if order matters:

>>> len(d2)                    # Number of entries in dictionary
3
>>> d2.has_key('ham')          # Key membership test (1 means true)
1
>>> 'ham' in d3                # Key membership test alternative
1
>>> d2.keys(  )                  # Create a new list of my keys.
['eggs', 'ham', 'spam']

Notice the third expression in this listing: the in membership test used for strings and lists also works on dictionaries—it checks if a key is stored in the dictionary, like the has_key method call of the prior line. Technically, this works because dictionaries define iterators that step through their keys lists. Other types provide iterators that reflect their common uses; files, for example, have iterators that read line by line; more on iterators in Chapter 14 and Chapter 21.

In Chapter 10, you’ll see that the last entry in Table 6-2 is another way to build dictionaries by passing lists of tuples to the new dict call (really, a type constructor), when we explore the zip function. It’s a way to construct a dictionary from key and value lists in a single call.

Changing Dictionaries in-Place

Dictionaries are mutable, so you can change, expand, and shrink them in-place without making new dictionaries, just like lists. Simply assign a value to a key to change or create the entry. The del statement works here too; it deletes the entry associated with the key specified as an index. Notice the nesting of a list inside a dictionary in this example (the value of key "ham“); all collection data types in Python can nest inside each other arbitrarily:

>>> d2['ham'] = ['grill', 'bake', 'fry']      # Change entry.
>>> d2
{'eggs': 3, 'spam': 2, 'ham': ['grill', 'bake', 'fry']}

>>> del d2['eggs']                            # Delete entry.
>>> d2
{'spam': 2, 'ham': ['grill', 'bake', 'fry']}

>>> d2['brunch'] = 'Bacon'                    # Add new entry.
>>> d2
{'brunch': 'Bacon', 'spam': 2, 'ham': ['grill', 'bake', 'fry']}

As with lists, assigning to an existing index in a dictionary changes its associated value. Unlike lists, whenever you assign a new dictionary key (one that hasn’t been assigned before), you create a new entry in the dictionary, as was done in the previous example for key 'brunch‘. This doesn’t work for lists, because Python considers an offset out of bounds if it’s beyond the end of a list, and throws an error. To expand a list, you need to use such tools as the append method or slice assignment instead.

More Dictionary Methods

Besides has_key, dictionary methods provide a variety of tools. For instance, the dictionary values and items methods return lists of the dictionary’s values and (key,value) pair tuples, respectively.

>>> d2.values(  ), d2.items(  )
([3, 1, 2], [('eggs', 3), ('ham', 1), ('spam', 2)])

Such lists are useful in loops that need to step through dictionary entries one by one. Fetching a nonexistent key is normally an error, but the get method returns a default value (None, or a passed-in default) if the key doesn’t exist.

>>> d2.get('spam'), d2.get('toast'), d2.get('toast', 88)
(2, None, 88)

The update method provides something similar to concatenation for dictionaries; it merges the keys and values of one dictionary into another, blindly overwiting values of the same key:

>>> d2
{'eggs': 3, 'ham': 1, 'spam': 2}
>>> d3 = {'toast':4, 'muffin':5}
>>> d2.update(d3)
>>> d2
{'toast': 4, 'muffin': 5, 'eggs': 3, 'ham': 1, 'spam': 2}

Dictionaries also provide a copy method; more on this method in the next chapter. In fact, dictionaries come with more methods than those listed in Table 6-2; see the Python library manual or other documentation sources for a comprehensive list.

A Languages Table

Here is a more realistic dictionary example. The following example creates a table that maps programming language names (the keys) to their creators (the values). You fetch a creator name by indexing on language name:

>>> table = {'Python':  'Guido van Rossum',
...          'Perl':    'Larry Wall',
...          'Tcl':     'John Ousterhout' }
...
>>> language = 'Python'
>>> creator  = table[language]
>>> creator
'Guido van Rossum'

>>> for lang in table.keys(  ): 
...     print lang, '	', table[lang]
...
Tcl     John Ousterhout
Python  Guido van Rossum
Perl    Larry Wall

The last command uses a for loop, which we haven’t covered yet. If you aren’t familiar with for loops, this command simply iterates through each key in the table and prints a tab-separated list of keys and their values. See Chapter 10 for more on for loops.

Because dictionaries aren’t sequences, you can’t iterate over them directly with a for statement, in the way you can with strings and lists. But if you need to step through the items in a dictionary it’s easy: calling the dictionary keys method returns a list of all stored keys you can iterate through with a for. If needed, you can index from key to value inside the for loop as done in this code.

Python also lets us step through a dictionary’s keys list without actually calling the keys method in most for loops. For any dictionary D, saying for key in D: works the same as saying the complete for key in D.keys( ):. This is really just another instance of the iterators mentioned earlier, which allow the in membership to work on dictionaries as well.

Dictionary Usage Notes

Here are a few additional details you should be aware of when using dictionaries:

  • Sequence operations don’t work. Dictionaries are mappings, not sequences; because there’s no notion of ordering among their items, things like concatenation (an ordered joining) and slicing (extracting contiguous section) simply don’t apply. In fact, Python raises an error when your code runs, if you try to do such things.

  • Assigning to new indexes adds entries. Keys can be created either when you write a dictionary literal (in which case they are embedded in the literal itself), or when you assign values to new keys of an existing dictionary object. The end result is the same.

  • Keys need not always be strings. Our examples used strings as keys, but any other immutable objects (not lists) work just as well. In fact, you could use integers as keys, which makes a dictionary look much like a list (when indexing, at least). Tuples are sometimes used as dictionary keys too, allowing for compound key values. And class instance objects (discussed in Part VI) can be used as keys too, as long as they have the proper protocol methods; roughly, they need to tell Python that their values won’t change, or else they would be useless as fixed keys.

Using dictionaries to simulate flexible lists

When you use lists, it is illegal to assign to an offset that is off the end of the list:

>>> L = [  ]
>>> L[99] = 'spam'
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
IndexError: list assignment index out of range

Although you could use repetition to pre-allocate as big a list as you’ll need (e.g., [0]*100), you can also do something that looks similar with dictionaries, which does not require such space allocations. By using integer keys, dictionaries can emulate lists that seem to grow on offset assignment:

>>> D = {  }
>>> D[99] = 'spam'
>>> D[99]
'spam'
>>> D
{99: 'spam'}

Here, it almost looks as if D is a 100-item list, but it’s really a dictionary with a single entry; the value of key 99 is the string 'spam‘. You’re able to access this structure with offsets much like a list, but you don’t have to allocate space for all the positions you might ever need to assign values to in the future.

Using dictionaries for sparse data structures

In a similar way, dictionary keys are also commonly leveraged to implement sparse data structures—for example, multidimensional arrays, where only a few positions have values stored in them:

>>> Matrix = {  }
>>> Matrix[(2,3,4)] = 88
>>> Matrix[(7,8,9)] = 99
>>>
>>> X = 2; Y = 3; Z = 4              # ; separates statements.
>>> Matrix[(X,Y,Z)]
88
>>> Matrix
{(2, 3, 4): 88, (7, 8, 9): 99}

Here, we use a dictionary to represent a three-dimensional array, all of which are empty except for the two positions, (2,3,4) and (7,8,8). The keys are tuples that record the coordinates of nonempty slots. Rather than allocating a large and mostly empty three-dimensional matrix, we can use a simple two-item dictionary. In this scheme, accessing empty slots triggers a nonexistent key exception—these slots are not physically stored:

>>> Matrix[(2,3,6)]
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
KeyError: (2, 3, 6)

If we want to fill in a default value instead of getting an error message here, there are at least three ways we can handle such cases. We can either test for keys ahead of time in if statements, use the try statement to catch and recover from the exception explicitly, or simply use the dictionary get method shown earlier to provide a default for keys that do not exist:

>>> if Matrix.has_key((2,3,6)):     # Check for key before fetch.
...     print Matrix[(2,3,6)]
... else:
...     print 0
...
0
>>> try:
...     print Matrix[(2,3,6)]       # Try to index.
... except KeyError:                # Catch and recover.
...     print 0
...
0 
>>> Matrix.get((2,3,4), 0)          # Exists; fetch and return.
88 
>>> Matrix.get((2,3,6), 0)          # Doesn't exist; use default arg.
0

We’ll study the if and try statements later.

Using dictionaries as “records”

As you can see, dictionaries can play many roles in Python. In general, they can replace search data structures (since indexing by key is a search operation), and represent many types of structured information. For example, dictionaries are one of many ways to describe the properties of an item in your program’s domain; they can serve the same role as “records” or “structs” in other languages:

>>> rec = {  }
>>> rec['name'] = 'mel'
>>> rec['age']  = 41
>>> rec['job']  = 'trainer/writer'
>>>
>>> print rec['name']
mel

This example fills out the dictionary by assigning to new keys over time. Especially when nested, Python’s built-in data types allow us to easily represent structured information:

>>> mel = {'name': 'Mark',
...        'jobs': ['trainer', 'writer'],
...        'web':  'www.rmi.net/~lutz',
...        'home': {'state': 'CO', 'zip':80501}}

This example uses a dictionary to capture object properties again, but has coded it all at once (rather than assigning to each key separately), and has nested a list and a dictionary to represent structure property values. To fetch components of nested objects, simply string together indexing operations:

>>> mel['name']
'Mark'
>>> mel['jobs']
['trainer', 'writer']
>>> mel['jobs'][1]
'writer'
>>> mel['home']['zip']
80501

Finally, note that more ways to build dictionaries may emerge over time. In Python 2.3, for example, the calls dict(name='mel', age=41) and dict([('name','bob'), ('age',30)]) also build two-key dictionaries. See Chapter 10, Chapter 13, and Chapter 27 for more details.



[1] In practice, you won’t see many lists written out like this in list-processing programs. It’s more common to see code that processes lists constructed dynamically (at runtime). In fact, although literal syntax is important to master, most data structures in Python are built by running program code at runtime.

[2] This description needs elaboration when the value and slice being assigned overlap: L[2:5]=L[3:6], for instance, works fine, because the value to be inserted is fetched before the deletion happens on the left.

[3] Unlike + concatenation, append doesn’t have to generate new objects, and so is usually faster. You can also mimic append with clever slice assignments: L[len(L):]=[X] is like L.append(X), and L[:0]=[X] is like appending at the front of a list. Both delete an empty slice and insert X, changing L in place quickly like append.

[4] The same note about the relative rarity of literals applies here: dictionaries are often built up by assigning to new keys at runtime, rather than writing literals. But see the following section on changing dictionaries; lists and dictionaries are grown in different ways. Assignment to new keys works for dictionaries, but fails for lists (lists are grown with append instead).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset