by Al Sweigart
Practice Questions
Q:
1. What is []?
Q:
2. How would you assign the value 'hello' as the third value in a list stored in a variable named spam? (Assume spam contains [2, 4, 6, 8, 10].)
For the following three questions, let’s say spam contains the list ['a', 'b', 'c', 'd'].
Q:
3. What does spam[int(int('3' * 2) / 11)] evaluate to?
Q:
4. What does spam[-1] evaluate to?
Q:
5. What does spam[:2] evaluate to?
For the following three questions, let’s say bacon contains the list [3.14, 'cat', 11, 'cat', True].
Q:
6. What does bacon.index('cat') evaluate to?
Q:
7. What does bacon.append(99) make the list value in bacon look like?
Q:
8. What does bacon.remove('cat') make the list value in bacon look like?
Q:
9. What are the operators for list concatenation and list replication?
Q:
10. What is the difference between the append() and insert() list methods?
Q:
11. What are two ways to remove values from a list?
Q:
12. Name a few ways that list values are similar to string values.
Q:
13. What is the difference between lists and tuples?
Q:
14. How do you type the tuple value that has just the integer value 42 in it?
Q:
15. How can you get the tuple form of a list value? How can you get the list form of a tuple value?
Q:
16. Variables that “contain” list values don’t actually contain lists directly. What do they contain instead?
Q:
17. What is the difference between copy.copy() and copy.deepcopy()?
Practice Projects
For practice, write programs to do the following tasks.
Comma Code
Say you have a list value like this:
spam = ['apples', 'bananas', 'tofu', 'cats']
Write a function that takes a list value as an argument and returns a string with all the items separated by a comma and a space, with and inserted before the last item. For example, passing the previous spam list to the function would return 'apples, bananas, tofu, and cats'. But your function should be able to work with any list value passed to it.
Character Picture Grid
Say you have a list of lists where each value in the inner lists is a one-character string, like this:
grid = [['.', '.', '.', '.', '.', '.'], ['.', 'O', 'O', '.', '.', '.'], ['O', 'O', 'O', 'O', '.', '.'], ['O', 'O', 'O', 'O', 'O', '.'], ['.', 'O', 'O', 'O', 'O', 'O'], ['O', 'O', 'O', 'O', 'O', '.'], ['O', 'O', 'O', 'O', '.', '.'], ['.', 'O', 'O', '.', '.', '.'], ['.', '.', '.', '.', '.', '.']]
You can think of grid[x][y] as being the character at the x- and y-coordinates of a “picture” drawn with text characters. The (0, 0) origin will be in the upper-left corner, the x-coordinates increase going right, and the y-coordinates increase going down.
Copy the previous grid value, and write code that uses it to print the image.
..OO.OO.. .OOOOOOO. .OOOOOOO. ..OOOOO.. ...OOO... ....O....
Hint: You will need to use a loop in a loop in order to print grid[0][0], then grid[1][0], then grid[2][0], and so on, up to grid[8][0]. This will finish the first row, so then print a newline. Then your program should print grid[0][1], then grid[1][1], then grid[2][1], and so on. The last thing your program will print is grid[8][5].
Also, remember to pass the end keyword argument to print() if you don’t want a newline printed automatically after each print() call.
Chapter 5. Dictionaries and Structuring Data
In this chapter, I will cover the dictionary data type, which provides a flexible way to access and organize data. Then, combining dictionaries with your knowledge of lists from the previous chapter, you’ll learn how to create a data structure to model a tic-tac-toe board.
The Dictionary Data Type
Like a list, a dictionary is a collection of many values. But unlike indexes for lists, indexes for dictionaries can use many different data types, not just integers. Indexes for dictionaries are called keys, and a key with its associated value is called a key-value pair.
In code, a dictionary is typed with braces, {}. Enter the following into the interactive shell:
>>> myCat = {'size': 'fat', 'color': 'gray', 'disposition': 'loud'}
This assigns a dictionary to the myCat variable. This dictionary’s keys are 'size', 'color', and 'disposition'. The values for these keys are 'fat', 'gray', and 'loud', respectively. You can access these values through their keys:
>>> myCat['size'] 'fat' >>> 'My cat has ' + myCat['color'] + ' fur.' 'My cat has gray fur.'
Dictionaries can still use integer values as keys, just like lists use integers for indexes, but they do not have to start at 0 and can be any number.
>>> spam = {12345: 'Luggage Combination', 42: 'The Answer'}
Dictionaries vs. Lists
Unlike lists, items in dictionaries are unordered. The first item in a list named spam would be spam[0]. But there is no “first” item in a dictionary. While the order of items matters for determining whether two lists are the same, it does not matter in what order the key-value pairs are typed in a dictionary. Enter the following into the interactive shell:
>>> spam = ['cats', 'dogs', 'moose'] >>> bacon = ['dogs', 'moose', 'cats'] >>> spam == bacon False >>> eggs = {'name': 'Zophie', 'species': 'cat', 'age': '8'} >>> ham = {'species': 'cat', 'age': '8', 'name': 'Zophie'} >>> eggs == ham True
Because dictionaries are not ordered, they can’t be sliced like lists.
Trying to access a key that does not exist in a dictionary will result in a KeyError error message, much like a list’s “out-of-range” IndexError error message. Enter the following into the interactive shell, and notice the error message that shows up because there is no 'color' key:
>>> spam = {'name': 'Zophie', 'age': 7} >>> spam['color'] Traceback (most recent call last): File "
Though dictionaries are not ordered, the fact that you can have arbitrary values for the keys allows you to organize your data in powerful ways. Say you wanted your program to store data about your friends’ birthdays. You can use a dictionary with the names as keys and the birthdays as values. Open a new file editor window and enter the following code. Save it as birthdays.py.
➊ birthdays = {'Alice': 'Apr 1', 'Bob': 'Dec 12', 'Carol': 'Mar 4'} while True: print('Enter a name: (blank to quit)') name = input() if name == '': break ➋ if name in birthdays: ➌ print(birthdays[name] + ' is the birthday of ' + name) else: print('I do not have birthday information for ' + name) print('What is their birthday?') bday = input() ➍ birthdays[name] = bday print('Birthday database updated.')
You create an initial dictionary and store it in birthdays ➊. You can see if the entered name exists as a key in the dictionary with the in keyword ➋, just as you did for lists. If the name is in the dictionary, you access the associated value using square brackets ➌; if not, you can add it using the same square bracket syntax combined with the assignment operator ➍.
When you run this program, it will look like this:
Enter a name: (blank to quit) Alice Apr 1 is the birthday of Alice Enter a name: (blank to quit) Eve I do not have birthday information for Eve What is their birthday? Dec 5 Birthday database updated. Enter a name: (blank to quit) Eve Dec 5 is the birthday of Eve Enter a name: (blank to quit)
Of course, all the data you enter in this program is forgotten when the program terminates. You’ll learn how to save data to files on the hard drive in Chapter 8.
The keys(), values(), and items() Methods
There are three dictionary methods that will return list-like values of the dictionary’s keys, values, or both keys and values: keys(), value
s(), and items(). The values returned by these methods are not true lists: They cannot be modified and do not have an append() method. But these data types (dict_keys, dict_values, and dict_items, respectively) can be used in for loops. To see how these methods work, enter the following into the interactive shell:
>>> spam = {'color': 'red', 'age': 42} >>> for v in spam.values(): print(v) red 42
Here, a for loop iterates over each of the values in the spam dictionary. A for loop can also iterate over the keys or both keys and values:
>>> for k in spam.keys(): print(k) color age >>> for i in spam.items(): print(i) ('color', 'red') ('age', 42)
Using the keys(), values(), and items() methods, a for loop can iterate over the keys, values, or key-value pairs in a dictionary, respectively. Notice that the values in the dict_items value returned by the items() method are tuples of the key and value.
If you want a true list from one of these methods, pass its list-like return value to the list() function. Enter the following into the interactive shell:
>>> spam = {'color': 'red', 'age': 42} >>> spam.keys() dict_keys(['color', 'age']) >>> list(spam.keys()) ['color', 'age']
The list(spam.keys()) line takes the dict_keys value returned from keys() and passes it to list(), which then returns a list value of ['color', 'age'].
You can also use the multiple assignment trick in a for loop to assign the key and value to separate variables. Enter the following into the interactive shell:
>>> spam = {'color': 'red', 'age': 42} >>> for k, v in spam.items(): print('Key: ' + k + ' Value: ' + str(v)) Key: age Value: 42 Key: color Value: red
Checking Whether a Key or Value Exists in a Dictionary
Recall from the previous chapter that the in and not in operators can check whether a value exists in a list. You can also use these operators to see whether a certain key or value exists in a dictionary. Enter the following into the interactive shell:
>>> spam = {'name': 'Zophie', 'age': 7} >>> 'name' in spam.keys() True >>> 'Zophie' in spam.values() True >>> 'color' in spam.keys() False >>> 'color' not in spam.keys() True >>> 'color' in spam False
In the previous example, notice that 'color' in spam is essentially a shorter version of writing 'color' in spam.keys(). This is always the case: If you ever want to check whether a value is (or isn’t) a key in the dictionary, you can simply use the in (or not in) keyword with the dictionary value itself.
The get() Method
It’s tedious to check whether a key exists in a dictionary before accessing that key’s value. Fortunately, dictionaries have a get() method that takes two arguments: the key of the value to retrieve and a fallback value to return if that key does not exist.
Enter the following into the interactive shell:
>>> picnicItems = {'apples': 5, 'cups': 2} >>> 'I am bringing ' + str(picnicItems.get('cups', 0)) + ' cups.' 'I am bringing 2 cups.' >>> 'I am bringing ' + str(picnicItems.get('eggs', 0)) + ' eggs.' 'I am bringing 0 eggs.'
Because there is no 'eggs' key in the picnicItems dictionary, the default value 0 is returned by the get() method. Without using get(), the code would have caused an error message, such as in the following example:
>>> picnicItems = {'apples': 5, 'cups': 2} >>> 'I am bringing ' + str(picnicItems['eggs']) + ' eggs.' Traceback (most recent call last): File "
The setdefault() Method
You’ll often have to set a value in a dictionary for a certain key only if that key does not already have a value. The code looks something like this:
spam = {'name': 'Pooka', 'age': 5} if 'color' not in spam: spam['color'] = 'black'
The setdefault() method offers a way to do this in one line of code. The first argument passed to the method is the key to check for, and the second argument is the value to set at that key if the key does not exist. If the key does exist, the setdefault() method returns the key’s value. Enter the following into the interactive shell:
>>> spam = {'name': 'Pooka', 'age': 5} >>> spam.setdefault('color', 'black') 'black' >>> spam {'color': 'black', 'age': 5, 'name': 'Pooka'} >>> spam.setdefault('color', 'white') 'black' >>> spam {'color': 'black', 'age': 5, 'name': 'Pooka'}
The first time setdefault() is called, the dictionary in spam changes to {'color': 'black', 'age': 5, 'name': 'Pooka'}. The method returns the value 'black' because this is now the value set for the key 'color'. When spam.setdefault('color', 'white') is called next, the value for that key is not changed to 'white' because spam already has a key named 'color'.
The setdefault() method is a nice shortcut to ensure that a key exists. Here is a short program that counts the number of occurrences of each letter in a string. Open the file editor window and enter the following code, saving it as characterCount.py:
message = 'It was a bright cold day in April, and the clocks were striking thirteen.' count = {} for character in message: count.setdefault(character, 0) count[character] = count[character] + 1 print(count)
The program loops over each character in the message variable’s string, counting how often each character appears. The setdefault() method call ensures that the key is in the count dictionary (with a default value of 0) so the program doesn’t throw a KeyError error when count[character] = count[character] + 1 is executed. When you run this program, the output will look like this:
{' ': 13, ',': 1, '.': 1, 'A': 1, 'I': 1, 'a': 4, 'c': 3, 'b': 1, 'e': 5, 'd': 3, 'g': 2, 'i': 6, 'h': 3, 'k': 2, 'l': 3, 'o': 2, 'n': 4, 'p': 1, 's': 3, 'r': 5, 't': 6, 'w': 2, 'y': 1}
From the output, you can see that the lowercase letter c appears 3 times, the space character appears 13 times, and the uppercase letter A appears 1 time. This program will work no matter what string is inside the message variable, even if the string is millions of characters long!
Pretty Printing
If you import the pprint module into your programs, you’ll have access to the pprint() and pformat() functions that will “pretty print” a dictionary’s values. This is helpful when you want a cleaner display of the items in a dictionary than what print() provides. Modify the previous characterCount.py program and save it as prettyCharacterCount.py.
import pprint message = 'It was a bright cold day in April, and the clocks were striking thirteen.' count = {} for character in message: count.setdefault(character, 0) count[character] = count[character] + 1 pprint.pprint(count)
This time, when the program is run, the output looks much cleaner, with the keys sorted.
{' ': 13, ',': 1, '.': 1, 'A': 1, 'I': 1, 'a': 4, 'b': 1, 'c': 3, 'd': 3, 'e': 5, 'g': 2, 'h': 3, 'i': 6, 'k': 2, 'l': 3, 'n': 4, 'o': 2, 'p': 1, 'r': 5, 's': 3, 't': 6, 'w': 2, 'y': 1}
The pprint.pprint() function is especially helpful when the dictionary itself contains nested lists or dictionaries.
If you want to obtain the prettified text as a string value instead of displaying it on the screen, call pprint.pformat() instead. These two lines are equivalent to each other:
pprint.pprint(someDictionaryValue) print(pprint.pformat(someDictionaryValue))
Using Data Structures to Model Real-World Things
Even before the Internet, it was possible to play a game of chess with someone on the other side of the world. Each player would set up a chessboard at their home and then take turns mailing a postcard to each other describing each move. To do this, the players needed a way to unambiguously describe the state of the board and their moves.
In algebraic chess notation, the spaces on the chessboard are identified by a number and letter coordinate, as in Figure 5-1.
Figure 5-1. The coordinates of a chessboard in algebraic chess notation
The chess pieces are identified by letters: K for king, Q for queen, R for rook, B for bishop, and N for knight. Describing a move uses the letter of the piece and the coordinates of its destination. A pair of these moves describes what happens in a single turn (with white going first); for instance, the notation 2. Nf3 Nc6 indicates that white mo
ved a knight to f3 and black moved a knight to c6 on the second turn of the game.
There’s a bit more to algebraic notation than this, but the point is that you can use it to unambiguously describe a game of chess without needing to be in front of a chessboard. Your opponent can even be on the other side of the world! In fact, you don’t even need a physical chess set if you have a good memory: You can just read the mailed chess moves and update boards you have in your imagination.
Computers have good memories. A program on a modern computer can easily store billions of strings like '2. Nf3 Nc6'. This is how computers can play chess without having a physical chessboard. They model data to represent a chessboard, and you can write code to work with this model.
This is where lists and dictionaries can come in. You can use them to model real-world things, like chessboards. For the first example, you’ll use a game that’s a little simpler than chess: tic-tac-toe.
A Tic-Tac-Toe Board