Book Read Free

Automate the Boring Stuff with Python

Page 8

by Al Sweigart


  Say you have the list ['cat', 'bat', 'rat', 'elephant'] stored in a variable named spam. The Python code spam[0] would evaluate to 'cat', and spam[1] would evaluate to 'bat', and so on. The integer inside the square brackets that follows the list is called an index. The first value in the list is at index 0, the second value is at index 1, the third value is at index 2, and so on. Figure 4-1 shows a list value assigned to spam, along with what the index expressions would evaluate to.

  Figure 4-1. A list value stored in the variable spam, showing which value each index refers to

  For example, type the following expressions into the interactive shell. Start by assigning a list to the variable spam.

  >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[0] 'cat' >>> spam[1] 'bat' >>> spam[2] 'rat' >>> spam[3] 'elephant' >>> ['cat', 'bat', 'rat', 'elephant'][3] 'elephant' ➊ >>> 'Hello ' + spam[0] ➋ 'Hello cat' >>> 'The ' + spam[1] + ' ate the ' + spam[0] + '.' 'The bat ate the cat.'

  Notice that the expression 'Hello ' + spam[0] ➊ evaluates to 'Hello ' + 'cat' because spam[0] evaluates to the string 'cat'. This expression in turn evaluates to the string value 'Hello cat' ➋.

  Python will give you an IndexError error message if you use an index that exceeds the number of values in your list value.

  >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[10000] Traceback (most recent call last): File "", line 1, in spam[10000] IndexError: list index out of range

  Indexes can be only integer values, not floats. The following example will cause a TypeError error:

  >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[1] 'bat' >>> spam[1.0] Traceback (most recent call last): File "", line 1, in spam[1.0] TypeError: list indices must be integers, not float >>> spam[int(1.0)] 'bat'

  Lists can also contain other list values. The values in these lists of lists can be accessed using multiple indexes, like so:

  >>> spam = [['cat', 'bat'], [10, 20, 30, 40, 50]] >>> spam[0] ['cat', 'bat'] >>> spam[0][1] 'bat' >>> spam[1][4] 50

  The first index dictates which list value to use, and the second indicates the value within the list value. For example, spam[0][1] prints 'bat', the second value in the first list. If you only use one index, the program will print the full list value at that index.

  Negative Indexes

  While indexes start at 0 and go up, you can also use negative integers for the index. The integer value -1 refers to the last index in a list, the value -2 refers to the second-to-last index in a list, and so on. Enter the following into the interactive shell:

  >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[-1] 'elephant' >>> spam[-3] 'bat' >>> 'The ' + spam[-1] + ' is afraid of the ' + spam[-3] + '.' 'The elephant is afraid of the bat.'

  Getting Sublists with Slices

  Just as an index can get a single value from a list, a slice can get several values from a list, in the form of a new list. A slice is typed between square brackets, like an index, but it has two integers separated by a colon. Notice the difference between indexes and slices.

  spam[2] is a list with an index (one integer).

  spam[1:4] is a list with a slice (two integers).

  In a slice, the first integer is the index where the slice starts. The second integer is the index where the slice ends. A slice goes up to, but will not include, the value at the second index. A slice evaluates to a new list value. Enter the following into the interactive shell:

  >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[0:4] ['cat', 'bat', 'rat', 'elephant'] >>> spam[1:3] ['bat', 'rat'] >>> spam[0:-1] ['cat', 'bat', 'rat']

  As a shortcut, you can leave out one or both of the indexes on either side of the colon in the slice. Leaving out the first index is the same as using 0, or the beginning of the list. Leaving out the second index is the same as using the length of the list, which will slice to the end of the list. Enter the following into the interactive shell:

  >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[:2] ['cat', 'bat'] >>> spam[1:] ['bat', 'rat', 'elephant'] >>> spam[:] ['cat', 'bat', 'rat', 'elephant']

  Getting a List’s Length with len()

  The len() function will return the number of values that are in a list value passed to it, just like it can count the number of characters in a string value. Enter the following into the interactive shell:

  >>> spam = ['cat', 'dog', 'moose'] >>> len(spam) 3

  Changing Values in a List with Indexes

  Normally a variable name goes on the left side of an assignment statement, like spam = 42. However, you can also use an index of a list to change the value at that index. For example, spam[1] = 'aardvark' means “Assign the value at index 1 in the list spam to the string 'aardvark'.” Enter the following into the interactive shell:

  >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam[1] = 'aardvark' >>> spam ['cat', 'aardvark', 'rat', 'elephant'] >>> spam[2] = spam[1] >>> spam ['cat', 'aardvark', 'aardvark', 'elephant'] >>> spam[-1] = 12345 >>> spam ['cat', 'aardvark', 'aardvark', 12345]

  List Concatenation and List Replication

  The + operator can combine two lists to create a new list value in the same way it combines two strings into a new string value. The * operator can also be used with a list and an integer value to replicate the list. Enter the following into the interactive shell:

  >>> [1, 2, 3] + ['A', 'B', 'C'] [1, 2, 3, 'A', 'B', 'C'] >>> ['X', 'Y', 'Z'] * 3 ['X', 'Y', 'Z', 'X', 'Y', 'Z', 'X', 'Y', 'Z'] >>> spam = [1, 2, 3] >>> spam = spam + ['A', 'B', 'C'] >>> spam [1, 2, 3, 'A', 'B', 'C']

  Removing Values from Lists with del Statements

  The del statement will delete values at an index in a list. All of the values in the list after the deleted value will be moved up one index. For example, enter the following into the interactive shell:

  >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> del spam[2] >>> spam ['cat', 'bat', 'elephant'] >>> del spam[2] >>> spam ['cat', 'bat']

  The del statement can also be used on a simple variable to delete it, as if it were an “unassignment” statement. If you try to use the variable after deleting it, you will get a NameError error because the variable no longer exists.

  In practice, you almost never need to delete simple variables. The del statement is mostly used to delete values from lists.

  Working with Lists

  When you first begin writing programs, it’s tempting to create many individual variables to store a group of similar values. For example, if I wanted to store the names of my cats, I might be tempted to write code like this:

  catName1 = 'Zophie' catName2 = 'Pooka' catName3 = 'Simon' catName4 = 'Lady Macbeth' catName5 = 'Fat-tail' catName6 = 'Miss Cleo'

  (I don’t actually own this many cats, I swear.) It turns out that this is a bad way to write code. For one thing, if the number of cats changes, your program will never be able to store more cats than you have variables. These types of programs also have a lot of duplicate or nearly identical code in them. Consider how much duplicate code is in the following program, which you should enter into the file editor and save as allMyCats1.py:

  print('Enter the name of cat 1:') catName1 = input() print('Enter the name of cat 2:') catName2 = input() print('Enter the name of cat 3:') catName3 = input() print('Enter the name of cat 4:') catName4 = input() print('Enter the name of cat 5:') catName5 = input() print('Enter the name of cat 6:') catName6 = input() print('The cat names are:') print(catName1 + ' ' + catName2 + ' ' + catName3 + ' ' + catName4 + ' ' + catName5 + ' ' + catName6)

  Instead of using multiple, repetitive variables, you can use a single variable that contains a list value. For example, here’s a new and improved version of the allMyCats1.py program. This new version uses a single list and can store any number of cats that the user types in. In a new file editor window, type the following source code and save it as allMyCats2.py:

  catNames = [] while True: print('Enter the name of cat ' + str(len(catNames) + 1) + ' (Or enter nothing to stop.):') name = input() if name == '': break catNames = ca
tNames + [name] # list concatenation print('The cat names are:') for name in catNames: print(' ' + name)

  When you run this program, the output will look something like this:

  Enter the name of cat 1 (Or enter nothing to stop.): Zophie Enter the name of cat 2 (Or enter nothing to stop.): Pooka Enter the name of cat 3 (Or enter nothing to stop.): Simon Enter the name of cat 4 (Or enter nothing to stop.): Lady Macbeth Enter the name of cat 5 (Or enter nothing to stop.): Fat-tail Enter the name of cat 6 (Or enter nothing to stop.): Miss Cleo Enter the name of cat 7 (Or enter nothing to stop.): The cat names are: Zophie Pooka Simon Lady Macbeth Fat-tail Miss Cleo

  The benefit of using a list is that your data is now in a structure, so your program is much more flexible in processing the data than it would be with several repetitive variables.

  Using for Loops with Lists

  In Chapter 2, you learned about using for loops to execute a block of code a certain number of times. Technically, a for loop repeats the code block once for each value in a list or list-like value. For example, if you ran this code:

  for i in range(4): print(i)

  the output of this program would be as follows:

  0 1 2 3

  This is because the return value from range(4) is a list-like value that Python considers similar to [0, 1, 2, 3]. The following program has the same output as the previous one:

  for i in [0, 1, 2, 3]: print(i)

  What the previous for loop actually does is loop through its clause with the variable i set to a successive value in the [0, 1, 2, 3] list in each iteration.

  Note

  In this book, I use the term list-like to refer to data types that are technically named sequences. You don’t need to know the technical definitions of this term, though.

  A common Python technique is to use range(len(someList)) with a for loop to iterate over the indexes of a list. For example, enter the following into the interactive shell:

  >>> supplies = ['pens', 'staplers', 'flame-throwers', 'binders'] >>> for i in range(len(supplies)): print('Index ' + str(i) + ' in supplies is: ' + supplies[i]) Index 0 in supplies is: pens Index 1 in supplies is: staplers Index 2 in supplies is: flame-throwers Index 3 in supplies is: binders

  Using range(len(supplies)) in the previously shown for loop is handy because the code in the loop can access the index (as the variable i) and the value at that index (as supplies[i]). Best of all, range(len(supplies)) will iterate through all the indexes of supplies, no matter how many items it contains.

  The in and not in Operators

  You can determine whether a value is or isn’t in a list with the in and not in operators. Like other operators, in and not in are used in expressions and connect two values: a value to look for in a list and the list where it may be found. These expressions will evaluate to a Boolean value. Enter the following into the interactive shell:

  >>> 'howdy' in ['hello', 'hi', 'howdy', 'heyas'] True >>> spam = ['hello', 'hi', 'howdy', 'heyas'] >>> 'cat' in spam False >>> 'howdy' not in spam False >>> 'cat' not in spam True

  For example, the following program lets the user type in a pet name and then checks to see whether the name is in a list of pets. Open a new file editor window, enter the following code, and save it as myPets.py:

  myPets = ['Zophie', 'Pooka', 'Fat-tail'] print('Enter a pet name:') name = input() if name not in myPets: print('I do not have a pet named ' + name) else: print(name + ' is my pet.')

  The output may look something like this:

  Enter a pet name: Footfoot I do not have a pet named Footfoot

  The Multiple Assignment Trick

  The multiple assignment trick is a shortcut that lets you assign multiple variables with the values in a list in one line of code. So instead of doing this:

  >>> cat = ['fat', 'black', 'loud'] >>> size = cat[0] >>> color = cat[1] >>> disposition = cat[2]

  you could type this line of code:

  >>> cat = ['fat', 'black', 'loud'] >>> size, color, disposition = cat

  The number of variables and the length of the list must be exactly equal, or Python will give you a ValueError:

  >>> cat = ['fat', 'black', 'loud'] >>> size, color, disposition, name = cat Traceback (most recent call last): File "", line 1, in size, color, disposition, name = cat ValueError: need more than 3 values to unpack

  Augmented Assignment Operators

  When assigning a value to a variable, you will frequently use the variable itself. For example, after assigning 42 to the variable spam, you would increase the value in spam by 1 with the following code:

  >>> spam = 42 >>> spam = spam + 1 >>> spam 43

  As a shortcut, you can use the augmented assignment operator += to do the same thing:

  >>> spam = 42 >>> spam += 1 >>> spam 43

  There are augmented assignment operators for the +, -, *, /, and % operators, described in Table 4-1.

  Table 4-1. The Augmented Assignment Operators

  Augmented assignment statement

  Equivalent assignment statement

  spam += 1

  spam = spam + 1

  spam -= 1

  spam = spam - 1

  spam *= 1

  spam = spam * 1

  spam /= 1

  spam = spam / 1

  spam %= 1

  spam = spam % 1

  The += operator can also do string and list concatenation, and the *= operator can do string and list replication. Enter the following into the interactive shell:

  >>> spam = 'Hello' >>> spam += ' world!' >>> spam 'Hello world!'

  >>> bacon = ['Zophie'] >>> bacon *= 3 >>> bacon ['Zophie', 'Zophie', 'Zophie']

  Methods

  A method is the same thing as a function, except it is “called on” a value. For example, if a list value were stored in spam, you would call the index() list method (which I’ll explain next) on that list like so: spam.index('hello'). The method part comes after the value, separated by a period.

  Each data type has its own set of methods. The list data type, for example, has several useful methods for finding, adding, removing, and otherwise manipulating values in a list.

  Finding a Value in a List with the index() Method

  List values have an index() method that can be passed a value, and if that value exists in the list, the index of the value is returned. If the value isn’t in the list, then Python produces a ValueError error. Enter the following into the interactive shell:

  >>> spam = ['hello', 'hi', 'howdy', 'heyas'] >>> spam.index('hello') 0 >>> spam.index('heyas') 3 >>> spam.index('howdy howdy howdy') Traceback (most recent call last): File "", line 1, in spam.index('howdy howdy howdy') ValueError: 'howdy howdy howdy' is not in list

  When there are duplicates of the value in the list, the index of its first appearance is returned. Enter the following into the interactive shell, and notice that index() returns 1, not 3:

  >>> spam = ['Zophie', 'Pooka', 'Fat-tail', 'Pooka'] >>> spam.index('Pooka') 1

  Adding Values to Lists with the append() and insert() Methods

  To add new values to a list, use the append() and insert() methods. Enter the following into the interactive shell to call the append() method on a list value stored in the variable spam:

  >>> spam = ['cat', 'dog', 'bat'] >>> spam.append('moose') >>> spam ['cat', 'dog', 'bat', 'moose']

  The previous append() method call adds the argument to the end of the list. The insert() method can insert a value at any index in the list. The first argument to insert() is the index for the new value, and the second argument is the new value to be inserted. Enter the following into the interactive shell:

  >>> spam = ['cat', 'dog', 'bat'] >>> spam.insert(1, 'chicken') >>> spam ['cat', 'chicken', 'dog', 'bat']

  Notice that the code is spam.append('moose') and spam.insert(1, 'chicken'), not spam = spam.append('moose') and spam = spam.insert(1, 'chicken'). Neither append() nor insert() gives the new value of spam as its return value. (In fact, the return value of append() and insert() i
s None, so you definitely wouldn’t want to store this as the new variable value.) Rather, the list is modified in place. Modifying a list in place is covered in more detail later in Mutable and Immutable Data Types.

  Methods belong to a single data type. The append() and insert() methods are list methods and can be called only on list values, not on other values such as strings or integers. Enter the following into the interactive shell, and note the AttributeError error messages that show up:

  >>> eggs = 'hello' >>> eggs.append('world') Traceback (most recent call last): File "", line 1, in eggs.append('world') AttributeError: 'str' object has no attribute 'append' >>> bacon = 42 >>> bacon.insert(1, 'world') Traceback (most recent call last): File "", line 1, in bacon.insert(1, 'world') AttributeError: 'int' object has no attribute 'insert'

  Removing Values from Lists with remove()

  The remove() method is passed the value to be removed from the list it is called on. Enter the following into the interactive shell:

  >>> spam = ['cat', 'bat', 'rat', 'elephant'] >>> spam.remove('bat') >

‹ Prev