In this chapter, we’ll go over some Python features that we touched on in CSC110 but didn’t discuss as rigourously. We’ll be using most/all of these features in CSC111, so we’ve included this material to support your transition to that course!
range
and the
optional startRecall that range
is a special data type in Python that
represents a sequence of numbers:
>>> [x for x in range(1, 5)]
1, 2, 3, 4] [
So far, we’ve called range
with two arguments, a
start
and stop
. It turns out that the
start
argument is optional and has a default value
of 0
if not specified. That means that
range(0, n)
can be written equivalently as
range(n)
: This form harmonizes nicely with the fact that the
range
’s stop
argument is exclusive:
because of this, range(n)
has n
elements,
0, 1, ..., n - 1
.
>>> [x for x in range(5)]
0, 1, 2, 3, 4] [
Given any sequence Python data type (e.g., str
,
list
, tuple
), we know that we can use
indexing to access an element by index in the sequence:
>>> [10, 20, 30, 40][2]
30
>>> 'Hello'[4]
'o'
One common task is to access elements offset from the end of
the sequence rather than the front. For this, we can use indexing
with negative numbers: for a sequence seq
and positive
integer 0 < i < len(seq)
, seq[-i]
is
equivalent to seq[len(seq) - i]
. Here are some
examples: Our examples here only use the list
and
str
data types, but you know two other sequence data types:
tuple
and range
. We encourage you to try these
examples with those data types in the Python console!
>>> seq = [10, 20, 30, 40]
>>> seq[-1] # equivalent to seq[4 - 1] == seq[3]
40
>>> 'Hello'[-2] # equivalent to 'Hello'[5 - 2] == 'Hello'[3]
'l'
Warning: negative indexing is subject to index errors, just
like non-negative indexing! For example, the following raises an
IndexError
, since 10 > len('Hello')
:
>>> 'Hello'[-10]
Traceback (most recent call last):
...IndexError: string index out of range
Given a sequence seq
, we call seq[i]
a
(sequence) indexing operation. We have an additional
syntax that allows us to access a subsequence of the sequence
by specifying a start and stop index for a range of elements to retrive.
Formally, the following syntax is called a (sequence)
slicing operation:
seq[i:j]
Here, i
and j
are integers interpreted as
indexes into seq
, and the expression seq[i:j]
evaluates to a new sequence that:
seq
seq
with indexes between
i
and j
, where index i
is
inclusive and index j
is
exclusiveThis asymmetry is the same as the
start
/stop
of range
.Here are some examples:
>>> [10, 20, 30, 40][1:3]
20, 30]
[>>> 'Hello'[0:3]
'Hel'
Like the range
data type, sequence slicing allows for an
optional “start” index. If omitted, all elements from the start of the
sequence to the stop index (exclusive) are returned:
>>> 'Hello'[:3]
'Hel'
But slicing goes a step further and allows you to omit the stop index as well. In this case, all elements from the start index to the end of the sequence are returned:
>>> 'Hello'[3:]
'lo'
And finally, it’s possible to omit both the start and stop indexes in a slicing operation. In this case, a copy of the sequence with all of its elements is returned:
>>> 'Hello'[:]
'Hello'
So far, our range
and sequence slicing operations have
had an implicit “+1” when describing the range of numbers/indexes to
include. It turns out that Python allows both range
and
slicing to take an optional “step” value to allow the user to specify
other differences between consecutive numbers.
range(start, stop, step)
For range
, we do so by passing three arguments,
range(start, stop, step)
:
>>> [x for x in range(0, 10, 2)]
0, 2, 4, 6, 8]
[>>> [x for x in range(10, 0, -1)]
10, 9, 8, 7, 6, 5, 4, 3, 2, 1] [
That second example is interesting! There, the step
argument is -1
, and so the sequence decreases by 1
at each number, starting at 10
and stopping at
0
(exclusive).
seq[start:stop:step]
We can apply the same idea to sequence slicing by including an additional colon and step number:
>>> message = 'David is cool'
>>> message[0:10:2]
'Dvdi '
>>> message[10:0:-1]
'oc si diva'
Moreover, with a negative step we can still omit the “start” and “stop” indexes in a slicing operation. The behaviour is analogous to our above examples, except now an omitted “start” is interpreted as “start at the end of the sequence” and an omitted “stop” is interpreted as “stop at the beginning of the sequence”.
>>> message[4::-1]
'divaD'
>>> message[:4:-1]
'looc si '
>>> message[::-1]
'looc si divaD'
The last example, message[::-1]
, is a common Python
idiom for reversing a string and other types of sequences.