Programmer's Python Data - Sequences
Written by Mike James   
Monday, 11 December 2023
Article Index
Programmer's Python Data - Sequences
Slices
Modifying Sequences

You can create a new sequence from an existing one using slicing. A slice is a sub-sequence given by a start and end index. For example:

S[s:e]

is a new sequence starting as S[s] and ending at S[e-1]. S[e] isn’t included in the new sequence. That is, the new sequence is S[k] where s <= k <e.

A better representation is:

S[start:stop_before]

For example:

S[1:3] 

is the new sequence with elements S[1] and S[2].

The fact that the final element S[e] isn’t part of the new sequence is something that often leads to mistakes, but it is logical and even advantageous. The first thing to know is that if e in S[s:e] is more than the length of the sequence it is replaced by the length. For example:

S = [1,2,3]
print(S[0:42])

displays

[1,2,3]

That is, the 42 is replaced by 4 and S[0:4] is S[0], S[1] and S[3]. Since S[4] doesn’t exist it isn’t accessed. This allows you also to write:

S[0:len(S)]

to create a slice that is the whole of the sequence or a part of the sequence that includes the end. More generally:

S[s:e]

is a slice with e-s elements. This also lets you write:

S[s:s+n]

for a slice of n elements that starts at s.

As you can see, the convention that the final element isn’t included in the slice does have some advantages.

Also notice that there is a difference between indexing and slicing:

S[i]

is what the ith element contains and

S[i:i+1]

is a slice consisting of just the ith element.

For example:

S = [1,2,3]
print(S[2])
print(S[2:3])

displays

3
[3]

i.e. the integer 3 and a sequence with a single element containing 3.

Slices also differ in that they can include elements that don’t exist in their specification. If you index an element that doesn’t exist then the result is an exception. For example:

S = [1,2,3]
print(S[4:5])
print(S[4])

displays [] the empty list and then throws an exception as S[4] doesn’t exist.

Slices can also be specified using negative values and in this case they are taken to reference elements starting at the end of the sequence as in the case of indexing. That is, any negative index included in a slice, -i say, is replaced by len(S)-i.

For example:

S = [1,2,3]
print(S[-3:-1])

displays [1,2] as S[-3:-1] is the same as S[0:2]. Notice that, while S[-1] is the final element of the sequence, S[-3:-1] doesn’t include the final element by the rule that a slice doesn’t include the final element specified. In fact, there isn’t a way to include the final element in a slice using a negative index. The reason for this is that -0 is the same as 0 and so:

S = [1,2,3]
print(S[-3:-0])

displays [] as it is the same as S[0:0] which is the empty sequence.

Also notice that you cannot generate an exception in slicing as, if the indices specified don’t make any sense, the empty sequence is returned. There is also an additional rule which avoids exceptions. If the end index specified is beyond the end of the sequence then it is replaced by len(S). For example:

S = [1,2,3]
print(S[1:42])

displays [2,3] as S[1:42] is the same as S[1:len(S)] or S[1:3].

The same idea applies to leaving out indices. If you leave out the first index then 0 is assumed and leaving out the final index results in len(S) being used. For example:

S = [1,2,3]
print(S[1:])

displays [2,3] as S[1:] is the same as S[1:len(S)] or S[1:3]. A useful shorthand for specifying a complete sequence is provided by S[:] which is taken to mean S[0:len(S)].

Some sequence types allow a step or stride parameter within a slice

S[s:e:k]

to pick out every kth element. For example:

S[1:6:2]

is the sequence S[1], S[3] and S[5]. In general, the elements selected are S[s+nk] for s+nk<e.

The slicing notation s:e:k is implemented using a slice object. A slice object can be used as a run-time alternative to the slicing notation. You can create a slice object using the slice built-in function:

s=slice(s,e,k)

which returns a slice object that specifies the same slice as [s:e:k] and can be used as S[s].

Indexing and Slicing Summary

  • Indexing S[i] accesses the object the element references. If the element doesn’t exist an exception is thrown.

  • Slicing S[s:e] gives a sequence of n elements n = e-s from S[s] to S[e-1]

  • S[s:s+1] is a sequence of one element (or the empty list) whereas S[s] is the object referenced by S[s] (or an exception).

  • If e > len(S) then e is set to len(S)

  • Slicing never causes an exception and S[s,s] is the empty sequence.

  • If either index in a slice is negative, -i say, the value is replaced by len(S)-i

  • If s is omitted it defaults to 0.

  • If e is omitted it defaults to len(S).

  • A slice can also specify a “stride” S[s:e:k] which selects elements, starting at s, k units apart and ending at the last element before S[e].



Last Updated ( Monday, 11 December 2023 )