In the last workshop we learned about lists. Let's review.
names = ['Asha', 'Michael', 'Arjun', 'Roland']
print(names[2])
list[i] refers to the ith element of list (where the count starts at 0). We can use this value and we can also change this value.
names[1] = 'Victoria'
print(names)
In Python, lists are objects. They have actions that they can do. We call these methods. For example, we can call method sort on the list of names.
names.sort()
print(names)
A method is very like a function, except that it acts on a particular object. It is as if we are telling the list to sort itself.
Like functions, methods can take parameters. The list method append takes one parameter and adds the parameter to the end of the list.
names.append('Golnaz')
print(names)
Let's use the append
method and a for loop that we learned last week to ask the user
to enter 5 integers and put them into a list. Each time we ask for an integer we will append it.
So what will be in our list before we start looping and asking? Nothing'
numbers = []
We can create an empty list by using the square brackets with no items. Now add one input statement to ask for the integer.
numbers = []
new_number = input("please enter an integer ")
Then append that integer we just received to our list.
numbers.append(new_number)
Now repeat this asking and appending 5 times by using a for
loop.
numbers = []
for i in range(5):
new_number = input("please enter an integer ")
numbers.append(new_number)
print (numbers)
But this isn't right. We wanted integers and we have strings. Remember that the values from the function input are always strings. If we want them to be converted to integers, we call the function int
.
numbers = []
for i in range(5):
new_number = int(input("please enter an integer"))
numbers.append(new_number)
print (numbers)
Iterating Over a List
So far we have learned that we can iterate over a list by using a for
loop to iterate over the indices of the elements. For example we did this:
for i in range(len(numbers)):
print(numbers[i])
numbers[i] = numbers[i] * 2
print("And now the list has changed and is", numbers)
If we don't want to change the elements of the list, there is another more common way to iterate over a list. It looks like this:
for item in numbers:
print(item)
Let's do a really easy task, just to make sure everyone is with me here. Use this type of loop to add up the total of all the numbers in our list and then print the total.
sum = 0
for item in numbers:
sum = sum + item
print("The sum is", sum)
Now let's do a more interesting example. Assume we have a list of names (maybe all the students in this workshop.) We don't want to change that list, but we want to make a new list that contains all the names from the original list that start with 'A'.
A_list = []
for name in names:
if name[0] == 'A':
A_list.append(name)
print ("original list", names)
print (" A list ", A_list)
Like lists, strings are also objects and have methods. One difference, though is that while some list methods (like sort and append) change the list, none of the string methods ever change a string.
So what good are they?
Like functions, methods can return a value. Many of the string methods, return another string. For example:
s = "hello"
t = s.upper()
print (s, t)
Notice that the string s
hasn't changed. But calling the method upper
on string 's'
, returned the string 'HELLO'
which we assigned to variable t
. Here is another example.
food = " Pad Thai "
fixed_food = food.strip()
print ("|",food, "|", fixed_food)
Notice that the print function inserted one space for each comma and that the function strip
remove the leading and trailing spaces from our string food
.
There are quite a lot of string methods and you can find the list in the online python documentation at https://docs.python.org/2/library/stdtypes.html#string-methods
Let's assume we have a list of strings that are supposed to be all in uppercase. But some errors got into the data and there are a few strings in the list that are not completely uppercase letters. Let's write a function together that prints out the elements of the list that are not all in uppercase. Let's also use this as an opportunity to review the design recipe.
We need a name for our function. Let's use find_mistakes
Next we write an example. We need to call find_mistakes
on a list and some of the entries (at least one) needs to be a mistake.
def find_mistakes(original_list):
"""
>>> find_mistakes(['AA', 'BB', 'oops', 'DD', 'xx'])
prints oops and prints xx
"""
pass
Above I've also added the def line which means I had to make up a name for the parameter. Next we add the type contract.
def find_mistakes(original_list):
""" (list of str) -> void
>>> find_mistakes(['AA', 'BB', 'oops', 'DD', 'xx'])
prints oops and prints xx
"""
pass
Notice that the return type is void
. That means that it doesn't return anything. Because
the effect of our function is to print something. But we aren't returning a value. Finally we
write a description of what the function should do.
def find_mistakes(original_list):
""" (list of str) -> void
Print the elements of original list that are not all uppercase.
>>> find_mistakes(['AA', 'BB', 'oops', 'DD', 'xx'])
prints oops and prints xx
"""
pass
Now we write the body. To figure out how to do this we look at how it was that we worked
out the examples. We see that we must have looped over the elements of original_list
and for each one, checked if it was made up only of uppercase letters. If it wasn't, we printed it. Let's add that code.
But for a single string, how do we decide if it is uppercase? There's a method for that.
isupper()
returns True
when the string is not-empty and is only uppercase letters.
def find_mistakes(original_list):
""" (list of str) -> void
Print the elements of original list that are not all uppercase.
>>> find_mistakes(['AA', 'BB', 'oops', 'DD', 'xx'])
prints oops and prints xx
"""
for item in original_list:
if not item.isupper():
print(item)
find_mistakes(['AA', 'BB', 'oops', 'DD', 'xx'])
Let's put together what we've learned so far and write a function that takes a list of strings and doesn't change the list. The function should return a new list that only contains the strings from the original list that contain only digits.
def keep_digits(original_list):
""" (list of str) -> list of str
>>> keep_digits(['98', 'a', '5'])
['98', '5']
Return a list of the elements of original_list that are composed only of digits
"""
result = []
for item in original_list:
if item.isdigit():
result.append(item)
return result
keep_digits(['98', 'a', '5'])
Note for Michael -- I wrote these notes for slicing and splicing not realizing that we had put these 2 topics in W4. We can just save them.
We say that list[i]
evalues to the ith element of list. list[i:j]
makes a new list that contains the elements from i
up to but not including j
.
fruit = ['Apples', 'Oranges', 'Pears', 'Bananas']
print(fruit[2:4])
print(fruit[1:-1])
print(fruit[:3])
last_fruit = fruit[-1:]
print(last_fruit)
Notice that negative indexing can be used. Notice that a : on either side of the comma gets that end of the list. Notice that even though the last list contains only one element, it is still a list.
We can also assign a list to a slice. This replaces the slice with the new list. The slice you replace and the replacement slice don't have to have the same number of elements. That means you can use splicing to increase or decrease lists.
# if the two list are the same size, it does as expected and just replaces them
fruit[1:3] = ['Navel Oranges', 'Anjou Pears']
print(fruit)
# but if you replace with an empty list, it removes items
fruit[2:3] = []
print(fruit)
# or you could replace a slice with a longer list
fruit[1:3] = ['beets', 'carrots', 'peppers', 'cabbage']
print(fruit)
# or you could replace an empty slice even
fruit[1:1] = ['chocolate']
print(fruit)
# notice that assigning a list to a slice of length 1
# is different than assigning a list to a single element
fruit[2] = ['X', 'Y']
print(fruit)
That last example, assigned a list into fruit[2]
. That's called a nested list and we will talk about them soon.
Now that we know about the loop for item in list
, let's try to use it to change our list.
Suppose we want to call tolower() on every item of a list to convert all the elements to lowercase. We could try to do it like this.
colours = ['White', 'BLUE', 'Red', 'yeLLow']
# we can convert any one element like this
colours[2] = colours[2].lower()
print(colours)
# now try to do this in a loop
for col in colours:
col = col.lower()
print(colours)
What's going on? The variable col
takes on successive values from the list. We can confirm this by printing out its value inside the loop. And we can see that calling lower()
works as
expected by printing out col
a second time.
colours = ['White', 'BLUE', 'Red', 'yeLLow']
# we can convert any one element like this
colours[2] = colours[2].lower()
print(colours)
# now try to do this in a loop
for col in colours:
print("The value of col is", col)
col = col.lower()
print("And then it is", col)
print(colours)
But these changed values are not assigned back to the list. col
is a separate variable that
at the top of each loop iteration is assigned the value of the next item in the list. It isn't connected to the element in the list. It just gets its value at the top of the list and then the loop body executes.
A good rule (for now) is that if you will need to change the value of the elements of the list
(not just use them), you need to loop over indices with for i in range(len(...))