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

Python takes a unique and very logical approach to basic data structures. As the next step up from numbers it has the sequence. Find out how it all works in this extract from Programmer's Python: Everything is Data.

Is now available as a print book: Amazon

Contents

1. Python – A Lightning Tour
2. The Basic Data Type – Numbers
Extract: Bignum
3. Truthy & Falsey
4. Dates & Times
5. Sequences, Lists & Tuples
Extract Sequences
6. Strings
Extract Unicode Strings
7. Regular Expressions
8. The Dictionary
Extract The Dictionary
9. Iterables, Sets & Generators
Extract  Iterables
10. Comprehensions
Extract  Comprehensions
11. Data Structures & Collections
Extract Stacks, Queues and Deques ***NEW!!!
12. Bits & Bit Manipulation
Extract Bits and BigNum
13. Bytes
Extract Bytes And Strings
Extract Byte Manipulation
14. Binary Files
15. Text Files
16. Creating Custom Data Classes
Extract A Custom Data Class
17. Python and Native Code
Extract   Native Code
Appendix I Python in Visual Studio Code
Appendix II C Programming Using Visual Studio Code

<ASIN:1871962765>

<ASIN:1871962749>

<ASIN:1871962595>

<ASIN:B0CK71TQ17>

<ASIN:187196265X>

This concept includes ideas that other languages divide up into different types of data – arrays, lists and strings. In Python there are sequences of different types that cross the usual divisions. In this chapter we cover lists, tuples and the range object. Other built-in sequences are strings, which are covered in the next chapter and bytes, bytearray and memoryview which are covered in Chapter 12.

What Is A Sequence?

A sequence is just a set of things indexed by the whole numbers starting counting from zero. Python has many implementation of sequences and you can create your own, but the archetypal sequence is the list and this is used in all the examples in this chapter, but notice the ideas are general. That is, a sequence is best thought of as a set of “mixin” methods that are present in a range of different objects.

Typically a particular element of a sequence is picked out using an index. S[i] is the ith element of S and it is usually allowed to be any Python object including another sequence. This use of square brackets is generally called index notation or indexing. S[0] is the first element of the sequence S and S[n-1] is the last element if it has a total of n elements. The built-in function len(S) returns the length of the sequence.

In general the elements of a sequence are references to objects and this can cause confusion if you are not expecting “reference” semantics. For example:

`S = [MyObject,0,MyObject]`

creates a sequence with S[0] and S[2] both referencing the same object. This means that any changes made to the object referenced by S[0] is made to the same object as referenced by S[2]. For example:

```S[0].myAttribute = 42
print(S[2].myAttribute)```

displays 42 assuming MyObject has a myAttribute attribute. In general, assignment to a sequence does not create a new copy of the object being assigned.

Lists

Elements are stored in sequences using assignment. Exactly how this is done depends on the type of sequence, but essentially it involves the use of a sequence literal. For example, a list literal is created by writing the elements between square brackets:

`S = [a,b,c]`

creates a list with elements S[0], S[1] and S[2] set to reference a, b and c respectively. Notice a, b and c are any Python objects you care to specify. Also notice that a special case is [] which creates an empty list.

You can also use the list constructor to convert any iterable into a list. An iterable is another mixin-like sequence that doesn’t support indexing but does support being iterated through from start to finish. For example, a tuple, see later, is a sequence but all sequences are iterables so you can convert a tuple to a list using:

`list((1,2,3))`

returns [1,2,3].

A more advanced way of creating a sequence is to use an “iterable” as part of a list comprehension or within the list constructor, see Chapter 9 which takes an in-depth look at iterables.

There are two basic operators, + and *, that work with sequences. The + operation “adds” two sequences together, that is:

`S = S1+S2`

creates a new sequence S with the elements of S1 followed by the elements of S2. The * operator repeats a sequence:

`S = S1*3`

creates a new sequence S with the elements of S1 repeated three times. It is equivalent to:

`S = S1+S1+S1`

There are also some standard methods that apply to all sequences:

 ` x in S` True if an item of S is equal to x, otherwise False ` x not in S` not(s in S) ` len(S)` length of S ` min(S)` smallest item of S ` max(s)` largest item of S ` S.index(x,i,j)` index of the first occurrence of x in S at or after index i and before index j. You can omit i or j. ` S.count(x)` total number of occurrences of x in S

Most of these are useful ways of avoiding having to write an explicit for loop and they are generally faster.

Sequences come in two forms, just like most other data structures, mutable and immutable. A mutable sequence is one in which you can change elements after it has been created. Obviously, an immutable sequence is one that cannot be changed. Python generally provides both mutable and non-mutable versions of sequences, but not always. For example, a list is mutable but a tuple is an immutable list. That is, after you have created a list you can change any element. For example:

```S = [1,2,3]
S[0] = 42```

produces the list [42,2,3]. If you try the same thing with a tuple you will generate an exception, more on tuples later.

You can also use negative indices and this are taken to refer to elements from the end of the sequence. That is S[-1] is the last element of the sequence. The way that this works is that if you use a negative index S[-i] this is converted to S[len(S)-i]. For example, with:

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

all of the print instructions display 3, the final value.

Any attempt to access an element which doesn’t exist results in an exception. For example:

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

generates an exception. Similarly negative values can result in an exception. For example:

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

which tries to access S[-1] which doesn’t exist as S[0] is the first element and notice that in this case the index isn’t modified – the adjustment to negative indices is applied only once.

The fact that you cannot reference non-existent elements also means that for mutable sequences you can’t create new elements by assignment. That is:

```S = [1,2,3]
S[4] = 42```

also generates an exception because S[4] doesn’t exist and assignment doesn’t create a new element, only changes existing elements. You can extend a sequence with new elements, but it is easier to understand how after we look at slices.

Last Updated ( Monday, 11 December 2023 )