Comp 112
Lecture 5
Lists and References2018.02.27
Lists are similar to strings, but more flexible in two ways:
The elements of a list can be of any type, not just characters.
Lists are mutable: they can be changed after being created.
To write a list, use brackets and commas:
The len
function is overloaded to work on lists:
Lists support indexing (_[_]
) and slicing (_[_:_]
) just like strings:
The operators for concatenation (_+_
) and repetition (_*_
) are overloaded to work on lists:
for
loops work on lists too, assigning the loop variable to each list element in turn:
The list
coercion function “explodes” a string into the list of its characters:
A homogeneous list is one where all of its elements have the same type.
In this course all lists will be homogeneous. (We’ll meet some non-homogeneous data structures later.)
To Python, the type of any list is just “list
”:
But we usually need to know the type of a list’s elements as well:
Signatures for homogeneous lists should specify the element type.
Unlike any type we’ve seen so far, the elements of list
type can be changed after being created.
The element located at a list index can be changed using index assignment:
A slice can be cut out of a list and a new list spliced into its place using slice assignment:
The list spliced in need not be the same length as the slice cut out.
If the list that is spliced in has length 0
, then this just cuts out a slice.
If the slice that is cut out has length 0
, then this just splices in a list.
Until we met lists, all the Python types we knew were immutable.
For example, it doesn’t matter whether or not two string variables refer to the same copy of 'hello'
,
because we can’t do index or slice assignment on strings to change them.
But with lists, it does matter.
Putting a list reference on the right side of an assignment causes the left side to refer to the same list.
This is called aliasing.
If we make changes to a list using one of its aliases then those changes are visible from any other alias too.
Use the “_is_
” or “_is not_
” operators to see whether two references alias the same value:
The “_==_
” and “_!=_
” operators compare list equality content-wise, not reference-wise, so they can’t detect aliasing.
When a list is passed to a function as an argument, the corresponding parameter becomes an alias to that list.
When a function makes changes to an argument list, that is a type of effect, called a mutation (or “modification”).
It’s important to understand whether a function acts by returning a new list or by mutating an argument list. Compare:
The list
namespace contains functions/methods that act on lists, often by mutation. For example:
All of these can be easily written in just a few lines using slice assignment.
Usually, to process a list we need to know the type of its elements (e.g. we can do arithmetic only with numbers).
But some operations work for any kind of list because they rely on only the list structure, not the element type.
Functions that act this way are called type-generic:
This function doesn’t examine the elements of the list in any way, that’s how it’s able to treat them generically.
The “a
” in “any a
” in the signature is a type parameter that can be assigned any type.
Python has a built-in function called “reversed
” that does the same thing, except that it returns an iterator.
An iterator is any type that can be iterated over with a for
loop. list
s are examples of iterators.
It is a quirk of Python that many built-in functions that we would expect to return list
s actually return other iterator
s instead.
For example, the range
function has signature: int , int -> iterator (int)
All we will care about iterator
s in this course is that they can be converted to list
s.
If indexing into an object that you think is a list causes an error, it may actually be a different iterator instead. Try converting it to a list with the list
coercion function.
One common use of for
loops is to process each element of a list in the same way:
This pattern is called mapping:
Python has a built-in function called “map
” that does the same thing:
Note that the first argument to the map
function is another function!
This makes map
a higher-order function: a function that manipulates other functions.
map
takes the argument function and applies it to each element of the argument list.
Higher-order functions like map
let you work at a higher level of abstraction
and free you from having to write repetitive bits of code.
Another common use of for
loops is to select from a list the elements that satisfy some predicate:
This pattern is called filtering a list. Python has a higher-order function called “filter
” to do this:
The first argument to filter
is a predicate (i.e. a bool
-valued function):
Reading:
Come to lab on Thursday.
Complete homework 5.
Review study guide for midterm 1