Chapter 20: Python: List and Tuple

The day before sports day, the physical education teacher gives you a job. Every student in your class will take part in the long jump, and you have to note down how far each one jumps. There are thirty students.

You would never draw thirty separate boxes on the page and label them Box 1, Box 2, Box 3, all the way to Box 30. You would rule one column, write the names one below the other, and put each reading beside its name. One page. One column. Thirty readings, still in order, and you can always point to the fifth one.

A program faces exactly the same problem. Until now, each name you created in Python held a single value, and a single value is fine for a single reading. Thirty readings need something else — one name that holds many values, kept in a fixed order.

There is a second half to the job as well. The list of events on the sports day card was decided weeks ago and must not be altered by anybody. Python has a way of storing that too. See Fig. 20.0-1.

Diagram

Fig. 20.0-1 – two labelled containers side by side. Left container drawn with square brackets [ ] and an open lid, holding four cards reading 3.2, 2.9, 3.5, 3.1, with small index labels 0, 1, 2, 3 below the cards, and two curved arrows showing a card being added and a card being taken out. Right container drawn with round brackets ( ) and a sealed lid, holding four cards reading 100 m, Long Jump, Relay, March Past, with the same index labels 0, 1, 2, 3 below, and a crossed-out arrow showing that no card can be added or taken out. Caption strip under the left container: “can be changed after it is made”; under the right container: “fixed once it is made”

NoteCuriosity Corner

Q1. Why is one name holding one value not enough when a program has to remember thirty readings? Q2. How does Python pick out just one value from a store that holds many? Q3. Can new values be added to a list after the list has already been created? Q4. If a tuple cannot be changed at all, what is the point of having one? Q5. Suppose values are kept in a tuple and one of them now has to be corrected. What can be done?

This chapter answers all five of these questions.

20.1 Holding Many Values in One Place

A variable is a name that a program uses to remember something. You write age = 15, and from that moment the name age stands for the value 15. If you later write age = 16, the old value is gone and the name holds the new one. One name, one value at a time.

That is enough for many small programs. It stops being enough the moment a program has to remember a set of things that belong together — the jump distances of a whole class, the names of the students in a group, the price of every item on a shop bill.

Doing it the long way

Suppose you measure three long jumps and want their total. With ordinary variables it can be done, and it is worth seeing exactly how it looks.

adding three jump distances kept in separate variables Problem: three jump distances have been measured in centimetres. Store them and print their total.

jump1 = 320
jump2 = 290
jump3 = 350

total = jump1 + jump2 + jump3
print("Total of three jumps:", total, "cm")

Output:

Total of three jumps: 960 cm

The program runs, and for three jumps it is perfectly reasonable. Now imagine the same idea for thirty students. You would have to invent thirty names, type thirty assignment lines, and write an addition with thirty terms in it. Miss one name and the total is quietly wrong.

There is a worse problem hiding behind the typing. A computer is good at repeating an instruction, but it can only repeat an instruction that stays the same each time. jump1, jump2 and jump3 are three different names, so a loop has no way to walk through them. The values are related in your head, but not in the program.

Q. Could you not just name them jump1 to jump30 and let a loop count from 1 to 30?

A. No. The loop can count 1, 2, 3 and so on, but it cannot glue that number onto the word “jump” to build a variable name. Python looks up names, not names made up while the program runs.

One name, many values

What a program needs is a single name that holds many values at once, kept in the order you put them in, so that the program can ask for the first value, the second value, or every value in turn. Fig. 20.1-1 shows the difference.

Diagram

Fig. 20.1-1 – two rows compared. Top row labelled “one name, one value”: a single box labelled age holding the value 15. Bottom row labelled “one name, many values”: a single label jumps with an arrow pointing to a strip of four joined boxes holding 320, 290, 350, 310 in that order, with the numbers 0, 1, 2, 3 written under the boxes. A curved arrow from the label to the strip is marked “the whole strip has one name”

Once the values sit together under one name, everything becomes easier. The program can add them all up, find the largest, sort them, count them, or go through them one by one — without knowing in advance how many there are.

Python gives you two ways of doing this. One of them lets you change the values afterwards; the other locks them once they are made. The rest of this chapter is about both.

Q1. Why is one name holding one value not enough when a program has to remember thirty readings?

A. Because thirty readings would need thirty separate names, which is long to type and easy to get wrong, and because a loop cannot move from one name to the next. Thirty names are thirty unrelated things as far as the program is concerned. Putting all thirty values under one name keeps them together and in order, so the program can work through them one after another.

20.2 Introduction to Lists

The single name that holds many values is called a list. A list keeps its values one after another, in the order you put them, and it lets you change them afterwards — add a new one, remove one, or replace one.

Each value stored inside a list is called an element of the list. The four jump distances 320, 290, 350 and 310 would be four elements of one list.

NoteDefinition

A list is a Python data type that stores several values under one name, keeps them in a fixed order, and allows them to be changed, added or removed after the list has been made.

Think of the attendance register in your class. It is one book, the names sit in a settled order, and the teacher can still add a new student at the end of the year or strike one off. That is exactly how a list behaves.

20.2.1 Creating a List

To create a list, write the values inside square brackets [ and ], separated by commas, and give the whole thing a name.

The values do not all have to be of the same kind. A list can hold whole numbers, decimal numbers, text, or a mixture of them. A list with nothing in it is written as an empty pair of brackets, and that is useful when values will only be added later while the program runs.

creating four different lists Problem: create a list of jump distances, a list of names, a list holding a mixture of types, and an empty list. Print each one.

jumps = [320, 290, 350, 310]
names = ["Anita", "Ravi", "Meera", "Farid"]
mixed = ["Anita", 320, True]
readings = []

print(jumps)
print(names)
print(mixed)
print(readings)

Output:

[320, 290, 350, 310]
['Anita', 'Ravi', 'Meera', 'Farid']
['Anita', 320, True]
[]

Notice two small things in the output. Python prints the brackets and commas back to you, so you can see the shape of the list at a glance. It also prints text values inside quotes, which is its way of showing that 320 and "320" would not be the same element.

leaving the quotes off text elements What goes wrong: writing names = [Anita, Ravi] without quotes. Python does not read Anita as a piece of text — it reads it as a variable name, cannot find any variable called Anita, and stops with a name error. The fix: put quotes around every text element — names = ["Anita", "Ravi"]. Numbers never take quotes.

Q. Is it wrong to keep names and numbers in the same list?

A. Python allows it, but be careful. If you later ask for the total of that list, adding a piece of text to a number will stop the program. Mixed lists are best kept for values that describe one thing, such as a name, a class and a roll number.

20.2.2 How a List Behaves

Four things about a list are worth fixing in your mind, because everything you do later in this chapter depends on them.

Order. The elements stay in the order you typed them. Python does not tidy them or sort them by itself. If the first jump you recorded was 320, then 320 stays first until you deliberately move it.

Position. Because the order is settled, every element has a definite place in the list — first, second, third — and Python lets you reach any one of them directly, without walking past the others. Section 20.3 shows how.

Repeats allowed. The same value may appear more than once. Two students can jump exactly 320 cm, and both readings belong in the list.

Changeable. A list is mutable, which means its contents can be changed after it has been created. You can replace an element, add new ones, or remove some. The name stays the same; what it holds does not have to.

order is kept and repeats are allowed Problem: store four colours, with one colour appearing twice, and show that Python keeps them exactly as they were written.

colours = ["red", "green", "red", "blue"]
print(colours)

Output:

['red', 'green', 'red', 'blue']

The two reds are two separate elements. Python has no reason to merge them or to move green out of the way.

Being mutable is what makes a list the natural choice for data that is still being collected — marks as they are entered, items as they are added to a bill, readings as they arrive from a sensor. A list also grows and shrinks on its own. You never have to say in advance how many elements it will hold, unlike some other languages where the size must be fixed before use.

the list What it is: one name that holds many values in a settled order. How it works: Python keeps the elements together and remembers each one’s position, so a program can reach any element directly or work through all of them in turn. Used for: holding the marks of a whole class while the average is being worked out. Watch out: because a list can be changed by any part of the program, values that must never change are not safe in one — a fixed list of examination subjects can be edited by mistake and nothing will warn you.

That last point is not a small one, and it is the reason Python offers a second, locked-up way of storing many values. You will meet it in 20.5.

20.3 Accessing the Elements of a List

Putting values into a list is only half the job. A program must also be able to take them out again — sometimes one particular value, sometimes a whole stretch of them.

20.3.1 Reaching One Element by Its Index

Every element of a list has a number that says where it sits. That number is called its index. Python counts the index from 0, so the first element has index 0, the second has index 1, and so on.

Counting from 0 looks odd at first. It becomes sensible if you read the index as how far this element is from the start rather than which one it is. The first element is at the start already, so it is 0 steps away.

To reach an element, write the name of the list followed by the index in square brackets. Python also accepts negative index numbers, which count backwards from the end: -1 is the last element, -2 the one before it. That saves you from working out the length of the list every time you want the final value. See Fig. 20.3-1.

Diagram

Fig. 20.3-1 – a horizontal strip of four joined boxes holding 320, 290, 350, 310, labelled jumps on the left. Above the boxes, the index numbers 0, 1, 2, 3 with small downward arrows. Below the boxes, the negative index numbers -4, -3, -2, -1 with small upward arrows. A note at the right end reads “index 4 does not exist”

reading single elements out of a list Problem: from a list of four jump distances, print the first jump, the third jump, and the last jump.

jumps = [320, 290, 350, 310]

print(jumps[0])
print(jumps[2])
print(jumps[-1])

Output:

320
350
310

The third jump is jumps[2], not jumps[3], because the counting starts at 0. And jumps[-1] gives 310 without the program needing to know that the list has four elements in it.

asking for an index that is one too far What goes wrong: a list of four elements has index numbers 0, 1, 2 and 3. Writing jumps[4] to get “the fourth jump” asks for a fifth element that is not there, and Python stops the program with an index error. The fix: the highest index is always one less than the number of elements. For the last element, use jumps[-1], which is right whatever the length of the list.

Q. What if the list is empty?

A. Then no index works at all, not even 0, because there is nothing at any position. A program that reads elements out of a list built while it is running should check that the list is not empty first.

Q2. How does Python pick out just one value from a store that holds many?

A. By its index — the position number written in square brackets after the name of the list. The first element is at index 0, the second at index 1, and so on, while negative numbers count back from the end. Python goes straight to that position instead of searching through the earlier elements.

20.3.2 Taking a Slice of a List

Sometimes one element is not what you want. You may need the first three marks, or everything from the fourth reading onwards. Taking a stretch of a list like this is called slicing.

A slice is written with two index numbers separated by a colon: marks[1:4]. The first number says where to start. The second number says where to stop — and Python stops just before it, so the element at that index is not included.

Either number may be left out. Leaving out the first means “from the very beginning”, and leaving out the second means “up to the very end”. A third number may be added, as in marks[::2], and it says how big a step to take — 2 means take every second element.

taking slices out of a list of marks Problem: from a list of six marks, print the second to fourth marks, the first three marks, everything from the fourth mark onwards, and every alternate mark.

marks = [45, 62, 78, 51, 90, 66]

print(marks[1:4])
print(marks[:3])
print(marks[3:])
print(marks[::2])

Output:

[62, 78, 51]
[45, 62, 78]
[51, 90, 66]
[45, 78, 90]

Look carefully at the first line of output. The slice marks[1:4] gives the elements at index 1, 2 and 3 — it stops before index 4, so the mark 90 is left out.

how many elements a slice contains

Given: a list marks with six elements, and the slice marks[1:4].

Find: the number of elements in the slice.

Working: the slice starts at index 1 and stops just before index 4, so it holds the elements at index 1, 2 and 3. Number of elements \(= \text{end} - \text{start} = 4 - 1 = 3\), where “start” is the first index number and “end” is the second.

3 elements.

expecting the last index to be included What goes wrong: writing marks[0:2] and expecting the first three marks. It gives only two — the elements at index 0 and 1. The fix: to get the first three, write marks[0:3] or simply marks[:3]. Remember that the second number is where Python stops, not the last element it takes.

One more thing is worth knowing. A slice does not disturb the original list — Python builds a fresh list out of the chosen elements and hands that back. The list marks still holds all six marks after every one of those four lines has run.

20.4 Operations on a List

A list is useful because it does not stay still. Values can be put in, taken out, replaced, arranged in order and looked for. Python provides ready-made instructions for all of this, so you never have to write the fiddly work yourself.

Most of these instructions are methods. A method is an instruction that belongs to a particular value and is written after it with a dot, like subjects.append("English"). Read it as: take the list called subjects, and append to it.

20.4.1 Adding Elements

A class list of subjects grows when a new subject is offered. A shopping bill grows with every item scanned. Python gives three ways of adding to a list, and they differ in where the new element goes and how many elements arrive.

  • append() puts one new element at the end of the list.
  • insert() puts one new element at a position you choose, and everything after it shifts along.
  • extend() takes a whole second list and adds all of its elements to the end, one by one.

adding subjects to a list in three ways Problem: begin with two subjects. Add English at the end, add Hindi in second place, then add two more subjects in one go.

subjects = ["Maths", "Science"]

subjects.append("English")
print(subjects)

subjects.insert(1, "Hindi")
print(subjects)

subjects.extend(["Computer", "Art"])
print(subjects)

Output:

['Maths', 'Science', 'English']
['Maths', 'Hindi', 'Science', 'English']
['Maths', 'Hindi', 'Science', 'English', 'Computer', 'Art']

Follow the second line of output carefully. insert(1, "Hindi") places Hindi at index 1, so Science, which was at index 1, moves to index 2, and English moves from index 2 to index 3. Nothing is lost; everything after the new element simply shifts one place to the right.

using append() when you mean extend() What goes wrong: writing subjects.append(["Computer", "Art"]). The list still grows by only one element, and that single element is itself a list. subjects then ends with ['Computer', 'Art'] sitting inside it as one item. The fix: use extend() when you are adding the contents of another list, and append() when you are adding one value.

Joining and repeating lists

Two lists can also be joined with the + sign, and a list can be repeated with the * sign. These do not change either of the original lists — they build a brand new list and hand it back.

joining two lists and repeating one Problem: join two groups of readings into one, and produce a list in which one group is repeated three times.

group1 = [10, 20]
group2 = [30, 40]

print(group1 + group2)
print(group1 * 3)
print(group1)

Output:

[10, 20, 30, 40]
[10, 20, 10, 20, 10, 20]
[10, 20]

The last line is the point of the example. After all that joining and repeating, group1 is untouched. If you want a list to actually change, use extend(); if you want a fresh list built out of two others, use +.

Q3. Can new values be added to a list after the list has already been created?

A. Yes. That is one of the main reasons for using a list. append() adds one value at the end, insert() puts one value at a chosen position and shifts the rest along, and extend() adds every element of another list at the end. The list simply grows; you never have to say in advance how big it will become.

20.4.2 Changing and Removing Elements

An element can be replaced by writing its index on the left of an equals sign. This is the same square-bracket notation you used for reading an element, only now it is being written to.

For removing, Python offers three methods that suit three different situations.

  • remove() takes the value you want gone and deletes the first element that matches it.
  • pop() takes the index you want gone, deletes that element, and hands the deleted value back so you can use it. With no index given, it removes the last element.
  • clear() empties the list completely, leaving the name in place with nothing in it.

correcting and removing marks Problem: correct the mark at index 2, remove the mark 51, take out the first mark and print what was taken, then empty the list.

marks = [45, 62, 78, 51, 90]

marks[2] = 80
print(marks)

marks.remove(51)
print(marks)

first = marks.pop(0)
print(first)
print(marks)

marks.clear()
print(marks)

Output:

[45, 62, 80, 51, 90]
[45, 62, 80, 90]
45
[62, 80, 90]
[]

Notice that pop() did two jobs at once — it removed 45 from the list and gave that value to the variable first. remove() gives nothing back; it only deletes.

giving remove() an index instead of a value What goes wrong: writing marks.remove(0) to delete the first mark. Python does not look at position here. It searches for an element whose value is 0, does not find one, and stops with an error. The fix: remove() needs the value — marks.remove(45). To delete by position, use marks.pop(0).

Q. What if the same value appears twice and you remove it?

A. Only the first one goes. remove() deletes the earliest matching element and leaves the rest alone, so removing it twice removes two of them.

20.4.3 Sorting a List

Marks are usually entered in roll-number order, but a merit list needs them in order of value. Rearranging the elements of a list into order is called sorting, and sort() does it.

By default sort() arranges elements in ascending order — smallest first for numbers, alphabetical for text. Adding reverse=True inside the brackets arranges them the other way round. A separate method, reverse(), does something different: it simply flips the list end for end, whatever order it happens to be in.

sorting marks and names Problem: sort five scores in ascending order, then in descending order. Sort four names alphabetically, then flip that order.

scores = [58, 91, 44, 76, 63]

scores.sort()
print("Ascending:", scores)

scores.sort(reverse=True)
print("Descending:", scores)

names = ["Ravi", "Anita", "Meera", "Farid"]
names.sort()
print("Names:", names)

names.reverse()
print("Flipped:", names)

Output:

Ascending: [44, 58, 63, 76, 91]
Descending: [91, 76, 63, 58, 44]
Names: ['Anita', 'Farid', 'Meera', 'Ravi']
Flipped: ['Ravi', 'Meera', 'Farid', 'Anita']

Both sort() and reverse() rearrange the list itself. The old order is gone for good, so if you still need the original order, make a copy of the list before sorting.

storing the result of sort() What goes wrong: writing scores = scores.sort(). The method does its work on the list and hands nothing back, so the name scores ends up holding the value None and the sorted list is lost. The fix: write scores.sort() on its own line, then use scores as usual.

One honest limitation: sorting works only when Python can compare the elements with one another. A list holding both numbers and text cannot be sorted, because there is no sensible answer to whether 45 comes before or after “Anita”, and the program stops with an error.

20.4.4 Searching in a List

Searching means answering one of two questions: is this value present at all? and where is it? The keyword in answers the first. The method index() answers the second, and count() tells you how many times the value occurs.

Before using them, it helps to know what Python is actually doing.

finding where a value sits in a list Input: a list, and the value being looked for. Output: the index of the first matching element, or the news that the value is not present. Steps:

1. Start at index 0.
2. Compare the element at that index with the value being looked for.
3. If they match, report that index and stop.
4. If they do not match, move on to the next index.
5. If the end of the list has been passed without a match, report that the value is not present.

Why it works: the elements are checked one after another from the beginning, so the first match found is bound to be the earliest one in the list.

checking for a subject and counting votes Problem: check whether Science is among the subjects, print where it sits, and count how many students voted yes.

subjects = ["Maths", "Hindi", "Science", "English"]

if "Science" in subjects:
    print("Science is in the list")

print(subjects.index("Science"))

votes = ["yes", "no", "yes", "yes", "no"]
print(votes.count("yes"))

Output:

Science is in the list
2
3

calling index() for a value that is not there What goes wrong: subjects.index("Music") when Music is not in the list. There is no index to report, so Python stops the program with a value error. The fix: check first with in, and only ask for the index if the value is present.

20.4.5 Counting and Summing with Built-in Functions

The last four instructions are not methods. They are ordinary functions, so the list goes inside the brackets rather than before a dot.

  • len() gives the number of elements in the list.
  • min() gives the smallest element.
  • max() gives the largest element.
  • sum() adds up all the elements, and needs them all to be numbers.

the size, smallest, largest and total of a list of marks Problem: for six marks, print how many there are, the lowest, the highest, and their total.

marks = [45, 62, 78, 51, 90, 66]

print(len(marks))
print(min(marks))
print(max(marks))
print(sum(marks))

Output:

6
45
90
392

Together, sum() and len() give you the average of a set of values without any counting by hand.

the average of the six marks

Given: the marks 45, 62, 78, 51, 90 and 66.

Find: the average mark.

Working: total \(= 45 + 62 + 78 + 51 + 90 + 66 = 392\) marks. Number of marks \(= 6\).

\[\text{average} = \frac{\text{total of the marks}}{\text{number of marks}} = \frac{392}{6} = 65.33\]

(rounded to two decimal places), where “total of the marks” is what sum() returns and “number of marks” is what len() returns.

65.33 marks.

Add one more mark of your own to the list with append(). Before running the program again, work out on paper what len() and sum() will now print, and then check whether you were right.

20.5 Introduction to Tuples

Not every set of values is meant to change. The order of events printed on a sports day card was settled weeks ago. The twelve months of the year are what they are. A set of subject codes handed to a school by the board is not for the school to edit.

If such values are kept in a list, nothing protects them. Any line anywhere in the program can append to that list or overwrite an element, and no warning is given. For values that are supposed to stay fixed, Python offers a second store called a tuple.

A tuple holds many values under one name and keeps them in order, exactly like a list. The one difference is that once a tuple has been made, it cannot be altered — no element can be replaced, added or removed.

NoteDefinition

A tuple is a Python data type that stores several values under one name and keeps them in a fixed order, but does not allow those values to be changed, added or removed after the tuple has been created.

20.5.1 Creating a Tuple

A tuple is written with round brackets ( and ) instead of square ones, with the values separated by commas.

Two small cases need care. A tuple with nothing in it is an empty pair of round brackets. A tuple with exactly one value must have a comma after that value, otherwise Python reads the brackets as ordinary brackets around a single value and no tuple is made at all.

creating four different tuples Problem: create a tuple of the sports day events, a tuple mixing types, a tuple with a single element, and an empty tuple. Print each one.

events = ("100 m", "Long Jump", "Relay", "March Past")
reading = (12, 45.5, "OK")
single = ("Relay",)
nothing = ()

print(events)
print(reading)
print(single)
print(nothing)

Output:

('100 m', 'Long Jump', 'Relay', 'March Past')
(12, 45.5, 'OK')
('Relay',)
()

Python prints the lone comma back to you in the third line. That comma is what makes single a tuple of one element rather than just the piece of text “Relay”.

forgetting the comma in a one-element tuple What goes wrong: writing single = ("Relay"). The brackets do nothing here, so single holds plain text, not a tuple. Asking for its length then gives 5, the number of letters, instead of 1. The fix: write single = ("Relay",). The comma, not the brackets, is what tells Python this is a tuple.

The round brackets can in fact be left out altogether — point = 3, 4 makes a tuple of two values. Putting several values together like this is called packing. Keep the brackets while you are learning, though, because they make the tuple visible to anyone reading your program.

A tuple may also hold another tuple as one of its elements, which is handy when each item is itself a small group of related values.

20.5.2 How a Tuple Behaves

A tuple keeps order in exactly the way a list does. The first value you wrote stays first, repeats are allowed, and every element has a position that can be used to reach it.

What is different is that a tuple is immutable — its contents cannot be changed after it is created. There is no append(), no insert(), no remove(), no sort(), and writing to a position is refused. If a program tries events[0] = "Relay", Python stops it with an error instead of quietly doing it.

a list gives way, a tuple does not Problem: show the same correction being made to a list and refused for a tuple.

marks = [45, 62, 78]
codes = (101, 102, 103)

marks[0] = 50
print(marks)

# codes[0] = 201 is not allowed and would stop the program
print(codes)

Output:

[50, 62, 78]
(101, 102, 103)

The commented-out line is the whole lesson. Remove the # and the program no longer runs — Python reports that a tuple does not support item assignment. That refusal is not a nuisance; it is the protection you asked for when you chose a tuple.

the tuple What it is: one name holding several values in a fixed order, locked against change. How it works: Python stores the values together and allows them to be read by position, but every instruction that would alter the contents is refused. Used for: holding a set of fixed subject codes, or the settled order of events in a school programme, so no part of the program can edit them by accident. Watch out: the lock is total. If even one value may need correcting later, a tuple is the wrong choice, and you would have to build a fresh tuple to make the change.

Because a tuple can never change, Python does not have to leave room for it to grow. This makes a tuple use slightly less memory than a list holding the same values, and makes it slightly quicker to create and read. For a handful of values you would never notice; over very large amounts of fixed data it is worth having.

Q4. If a tuple cannot be changed at all, what is the point of having one?

A. The lock is the point. Some data is supposed to stay fixed, and putting it in a tuple means no part of the program can alter it by mistake — an attempt to do so is refused straight away instead of passing unnoticed. Being fixed also lets Python store a tuple a little more compactly and read it a little faster than a list of the same values.

20.6 Working with Tuples

A tuple refuses to be changed, but it does not refuse to be used. Everything that only reads a tuple works just as it does for a list.

20.6.1 Accessing Elements of a Tuple

Indexing and slicing work exactly as you learnt them in 20.3. The index of the first element is 0, negative numbers count back from the end, and a slice written as start:end stops just before the end index.

The one difference to notice is the shape of what comes back. A slice of a list is a list; a slice of a tuple is a tuple, and it prints with round brackets.

reading events out of a tuple Problem: from the tuple of sports day events, print the first event, the last event, and the middle two events.

events = ("100 m", "Long Jump", "Relay", "March Past")

print(events[0])
print(events[-1])
print(events[1:3])

Output:

100 m
March Past
('Long Jump', 'Relay')

The first two lines print plain text, because a single element of this tuple is a piece of text. The third line prints a tuple, brackets and all, because a slice always hands back a group.

Q. Does taking a slice break the rule that a tuple cannot change?

A. No. Slicing does not touch the original tuple at all. Python builds a new tuple out of the chosen elements, and the tuple you sliced is exactly as it was.

20.6.2 Operations on a Tuple

Tuples support every operation that leaves the original alone.

Two tuples can be joined with +, and a tuple can be repeated with *. Neither changes the tuples involved — a brand new tuple is produced, which is why immutability is not broken.

joining and repeating tuples Problem: join two tuples of subject codes into one, repeat the first tuple twice, and print how many codes the joined tuple holds.

first = (101, 102)
second = (103, 104)

joined = first + second
print(joined)
print(first * 2)
print(len(joined))

Output:

(101, 102, 103, 104)
(101, 102, 101, 102)
4

len(), min() and max() work on a tuple in the same way as on a list. So do the two searching methods, count() and index(), and the keyword in for checking whether a value is present at all.

counting and locating values in a tuple Problem: for a tuple of five scores, print how many times 7 occurs, where 9 first occurs, and the lowest and highest scores.

scores = (7, 9, 7, 5, 7)

print(scores.count(7))
print(scores.index(9))
print(min(scores))
print(max(scores))

Output:

3
1
5
9

What a tuple does not have is any method that alters it. There is no append(), no remove(), no sort() and no clear(), because every one of those would change the contents.

Unpacking a tuple

A tuple is often used to keep a few related facts about one thing together — a name, a class and a section, say. Unpacking pulls those values out into separate variables in one line, with the names on the left matching the elements in order.

unpacking a student record Problem: store a student’s name, class and section in one tuple, then separate them into three variables and print them.

student = ("Anita", 10, "A")
name, standard, section = student

print(name)
print(standard)
print(section)

Output:

Anita
10
A

The number of names on the left must match the number of elements exactly. Three elements need three names; giving two or four stops the program.

A tuple may also hold other tuples. Writing pairs = ((101, "Maths"), (102, "Science")) gives a tuple of two elements, and each of those elements is itself a tuple of a code and a subject name. pairs[0] would then be the whole first pair, and pairs[0][1] would be the text “Maths”.

20.6.3 Deleting a Tuple

Single elements of a tuple cannot be deleted — that is what immutable means. The whole tuple, however, can be thrown away when the program has finished with it, using the del statement.

deleting an entire tuple Problem: create a tuple of subject codes, print it, and then delete it.

codes = (101, 102, 103)
print(codes)

del codes

Output:

(101, 102, 103)

After del codes runs, the name codes no longer exists. Using it again in the same program stops the program with a name error, because there is nothing left for Python to look up.

trying to delete one element of a tuple What goes wrong: writing del codes[0] to drop the first code. Python refuses, because removing an element would change the tuple. The fix: del may be used on the tuple as a whole. If one value really has to go, the tuple must be turned into a list first, which is what 20.8 is about.

20.7 Lists and Tuples Compared

Lists and tuples do the same basic job: they hold several values under one name, in a settled order, reachable by index. Almost everything you can read out of one, you can read out of the other. The difference is what happens when something tries to change them.

Table 20.1 – list vs tuple

Feature List Tuple
Written with Square brackets [ ] Round brackets ( )
Can it be changed? Yes — elements can be replaced, added or removed No — the contents are fixed once made
Adding and removing append(), insert(), extend(), remove(), pop(), clear() None of these exist
Rearranging sort() and reverse() change the list itself Neither exists
Reading elements Indexing and slicing Indexing and slicing, in the same way
Searching in, index(), count() in, index(), count()
Joining and repeating + and *, giving a new list + and *, giving a new tuple
Memory used Slightly more, since room is kept for growth Slightly less
Speed Slightly slower to create and read Slightly faster
Deleting Elements or the whole list may be deleted Only the whole tuple may be deleted, with del

If you are ever unsure which of the two a name is holding, ask Python.

telling a list and a tuple apart Problem: store the same three values as a list and as a tuple, and print what type each one is.

values_list = [5, 10, 15]
values_tuple = (5, 10, 15)

print(type(values_list))
print(type(values_tuple))

Output:

<class 'list'>
<class 'tuple'>
Choosing between them

The question to ask is not “which is better?” but “is this data still going to change?”

Use a list when values are being collected, corrected or reordered while the program runs — marks being entered one by one, items being added to a bill, names waiting to be sorted into a merit list. Growing and rearranging are exactly what a list is for.

Use a tuple when the values are settled and any change would be a mistake — a fixed set of subject codes, the order of events on a programme card, a group of facts about one person that belong together. Here the refusal to change is a safety catch, not an obstacle.

The difference in memory and speed is real but small. For the sizes of data you will meet in school programs, it should not decide anything. Choose on whether the data must stay fixed, and the rest follows.

Q. Can a list be an element of a tuple?

A. Yes, and it is worth knowing what that means. The tuple cannot be given a different element, but a list sitting inside it can still be changed. The lock is on the tuple itself, not on everything it holds.

Programs in school often hold real information about real students — names, marks, attendance. Keep only what the program actually needs, and never pass such a list around beyond the people who should see it. Putting the data in a tuple stops it being edited by accident, but it does nothing to stop it being shared wrongly. That part is up to the person writing the program.

Store the five values 58, 91, 44, 76 and 63 twice — once as a list, once as a tuple. Before you run anything, predict what will happen when you try sort() on each. Then run both lines and see which one Python refuses.

20.8 Converting a List into a Tuple and a Tuple into a List

Data does not always stay in the same state of readiness. Marks are collected one by one while the examination is being marked — that work needs a list. Once the marks are final and the result has been declared, nobody should be editing them any more, and a tuple is the safer place for them.

The reverse happens too. A tuple of subject codes is fixed, until the day a code is found to be wrong. The tuple itself cannot be corrected, but the values inside it can be moved somewhere that allows correction.

Python provides two functions for this. tuple() builds a tuple out of the values of a list, and list() builds a list out of the values of a tuple.

Locking a list once it is final

turning a finished list of marks into a tuple Problem: three marks have been collected in a list. Lock them into a tuple, and check what type the result is.

marks = [45, 62, 78]
locked = tuple(marks)

print(locked)
print(type(locked))
print(marks)

Output:

(45, 62, 78)
<class 'tuple'>
[45, 62, 78]

The last line is worth noticing. tuple() does not swallow the list or convert it in place — it reads the values and builds a separate tuple out of them. The list is still there afterwards, unchanged.

Correcting a value that is kept in a tuple

Suppose a tuple of subject codes holds 102 where it should hold 202, and a fourth code has to be added. The tuple cannot be edited, so the values are moved into a list, the changes are made there, and a fresh tuple is built from the result.

correcting a value that is kept in a tuple Input: a tuple, and the change that has to be made. Output: a new tuple with the change in place. Steps:

1. Build a list out of the tuple, using list().
2. Make the change in the list, which is allowed to change.
3. Build a new tuple out of the changed list, using tuple().
4. Let the old name refer to this new tuple.

Why it works: the original tuple is never altered, so its rule is not broken. A second tuple is made and the name is pointed at it instead.

editing tuple data by way of a list Problem: in a tuple of three subject codes, replace the second code with 202 and add a fourth code, 104. The result must again be a tuple.

codes = (101, 102, 103)

working = list(codes)
working[1] = 202
working.append(104)

codes = tuple(working)
print(codes)

Output:

(101, 202, 103, 104)

Q. So a tuple can be changed after all?

A. No. The tuple made in the first line was never touched. A different tuple was built from corrected values, and the name codes was pointed at the new one. The original is simply no longer used.

naming a variable list or tuple What goes wrong: writing list = [45, 62, 78]. The name list now holds your data, so list(codes) later in the program no longer calls the function and the program stops. The fix: choose names that describe the data — marks, codes, working — and leave list, tuple, sum and other built-in names alone.

Q5. Suppose values are kept in a tuple and one of them now has to be corrected. What can be done?

A. Build a list from the tuple with list(), make the correction in that list, then build a new tuple from it with tuple() and let the old name refer to the new tuple. The original tuple is never altered — it is replaced. Going the other way, tuple() locks a finished list once its values should stop changing.

20.9 Summary

  1. A variable holds one value at a time, which is not enough when a program has to remember a whole set of related values. Both a list and a tuple hold many values under one name, in a settled order.
  2. A list is written with square brackets and commas. Each value in it is called an element, and elements may be of different types, may repeat, and may be added or removed at any time.
  3. A list is mutable — its contents can be changed after it has been created. This makes it the right choice for data that is still being collected or corrected.
  4. Every element has an index giving its position, counted from 0 for the first element. Negative index numbers count back from the end, so -1 is the last element.
  5. Slicing takes a stretch of elements, written as start:end. Python stops just before the end index, and hands back a new list without disturbing the original.
  6. Elements are added with append() at the end, insert() at a chosen position, and extend() when a whole second list is to be added. The + sign joins two lists into a new one and * repeats a list.
  7. Elements are removed with remove() by value, pop() by index, and clear() for the whole contents. An element is replaced by writing to its index.
  8. sort() arranges a list in ascending order, or in descending order with reverse=True. reverse() simply flips the current order. Both change the list itself.
  9. Searching is done with in to check whether a value is present, index() to find where it first occurs, and count() to find how many times it occurs.
  10. len(), min(), max() and sum() give the number of elements, the smallest, the largest and the total of a list of numbers.
  11. A tuple is written with round brackets. A tuple of one element needs a comma after that element.
  12. A tuple is immutable — once created, no element can be replaced, added or removed. There is no append(), remove() or sort() for a tuple.
  13. Everything that only reads a tuple works as it does for a list: indexing, slicing, in, index(), count(), len(), min() and max(). Joining with + and repeating with * build a new tuple rather than changing the old one.
  14. Unpacking assigns the elements of a tuple to separate variables in one line, and the number of variables must match the number of elements.
  15. Single elements of a tuple cannot be deleted. The whole tuple can be removed with del.
  16. Choose a list when the data will still change, and a tuple when it must stay fixed. A tuple also uses slightly less memory and is slightly faster, though for small amounts of data the difference does not matter.
  17. tuple() builds a tuple from a list, and list() builds a list from a tuple. To correct a value kept in a tuple, convert it to a list, make the change, and build a new tuple from the result.

20.10 Key Terms

  1. Element – a single value stored inside a list or a tuple.

  2. Immutable – unable to be changed after it has been created; a tuple is immutable.

  3. Index – the position number of an element, counted from 0 for the first element, with negative numbers counting back from the end.

  4. List – a Python data type that holds several values under one name, keeps them in a fixed order, and allows them to be changed, added or removed.

  5. Method – an instruction that belongs to a particular value and is written after it with a dot, such as append() in marks.append(75).

  6. Mutable – able to be changed after it has been created; a list is mutable.

  7. Slicing – taking a stretch of elements from a list or tuple by writing a start index and an end index, with Python stopping just before the end index.

  8. Tuple – a Python data type that holds several values under one name in a fixed order, and does not allow them to be changed, added or removed once created.

20.11 Objective Questions

  1. Which of the following creates a tuple in Python?

    1. my_codes = [101, 102]
    2. my_codes = (101, 102)
    3. my_codes = {101, 102}
    4. my_codes = <101, 102>
  2. Fill in the blank: the index of the first element of a list is __________, and the index of its last element can also be written as __________.

  3. State whether the following statement is true or false: taking a slice of a tuple gives back a list.

  4. What will be printed by the following code?

subjects = ["Maths", "Science", "English"]
subjects.insert(1, "Hindi")
print(subjects[2])
  1. Hindi
  2. Science
  3. English
  4. Maths
  1. Match each instruction in Column A with what it does in Column B.
Column A Column B
a. append() i. empties the list completely
b. remove() ii. gives the position of the first matching element
c. index() iii. adds one element at the end of the list
d. clear() iv. deletes the first element having a given value
  1. Write the output of the following code.
marks = [45, 62, 78, 51, 90]
print(marks[1:3])
  1. Which one of the following can be done to a list but not to a tuple?
    1. Reading an element by its index
    2. Taking a slice
    3. Arranging the values in ascending order in place
    4. Counting how many times a value occurs

20.12 Concept Questions

  1. Define a tuple, and give one situation from school life in which a tuple would be a better choice than a list.

  2. Differentiate between append() and extend(). Support your answer with one short example of each.

  3. A list holds eight elements. Explain why its last element is at index 7, and give a way of reaching that element without knowing how many elements the list holds.

  4. A student writes scores = scores.sort() and then prints scores. What gets printed, and why does the sorted list not appear? Give the correct way of writing it.

  5. Write a program that stores the six marks 45, 62, 78, 51, 90 and 66 in a list, and then prints the number of marks, the lowest mark, the highest mark and their total.

  6. A tuple holds the subject codes (201, 202, 203, 204). The third code has to be corrected to 303. Write a program that makes this correction, so that the final result is again a tuple, and prints it.

20.13 Case-Based Questions

  1. The librarian of your school keeps a record of the books issued during the day. By closing time the record looks like this.
issued = ["Wings of Fire", "The Jungle Book", "Panchatantra", "The Jungle Book"]
  1. One more book, “Malgudi Days”, is issued just before closing. Write the instruction that adds it at the end of the record.
  2. The librarian wants to know how many times “The Jungle Book” was issued today. Which instruction gives this, and what value does it give for the record shown above?
  3. The librarian now wants the titles in alphabetical order. Name the method that does this, and state what happens to the order in which the books were actually issued.
  1. The order of events for sports day is printed on the programme card weeks in advance, and no part of the school’s program should be able to change it. It is stored like this.
events = ("100 m", "Long Jump", "Relay", "March Past")
  1. Give one reason for storing these events in a tuple rather than in a list.
  2. Write the output of print(events[-2]).
  3. On the morning of sports day the relay is dropped and shot put takes its place. Explain, step by step, how “Relay” can be replaced by “Shot Put” so that the final result is again a tuple, and write the program that does it.