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.

Programmer's Python
Everything is Data

Is now available as a print book: Amazon

pythondata360Contents

  1. Python – A Lightning Tour
  2. The Basic Data Type – Numbers
       Extract: Bignum
  3. Truthy & Falsey
  4. Dates & Times
       Extract Naive Dates ***NEW!!!
  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
      
    Extract Named Tuples and Counters
  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 )