Lesson-5.6
Tuples
Introduction
A tuple is an immutable sequence of values:
Tuples share a close resemblance to lists. They can be indexed and sliced just like lists:
The main point of difference between lists and tuples is that tuples cannot be updated in-place since they are immutable. So, the following operation will throw an error:
##### Alarm! Wrong code snippet! #####
numbers = ('one', 'two', 'four')
numbers[2] = 'three'
##### Alarm! Wrong code snippet! #####
The interpreter throws a TypeError
with the following message: TypeError: 'tuple' object does not support item assignment
. As a consequence, we cannot append or insert elements into a tuple. Likewise, elements in a tuple cannot be deleted. count
and index
are the only two methods which are defined for tuple
and they carry the usual meaning:
We can iterate through a tuple using for
:
Since tuples are immutable, they are passed by value in functions similar to other immutable types such as strings and numbers. As for functions that operate on tuples, sum
, max
, min
are useful ones.
More on Tuples
A few more points on tuples.
- A singleton tuple should be defined as follows:
Note the presence of a comma after the element. Let us see what happens if it is removed:
It is an integer!
- A list can be converted into a tuple and vice versa:
- A tuple can hold a non-homogeneous sequence of items:
- Membership can be determined using the
in
keyword:
- Tuples can be nested:
- A tuple can hold mutable objects.
The code given above runs without any errors. But we are trying to update the tuple in line-2. Aren't tuples immutable? Though a_tuple
is immutable, the element inside it is mutable. In any case, we aren't trying to change the sequence of objects inside the tuple, i.e., a_tuple[0]
continues to point to the same object. Let us verify this:
We see that the id
of the element inside the tuple remains unchanged. Thus the identities of the sequence of objects that make up a tuple can never change, and the interpreter will never allow that to change. If the objects inside the sequence are mutable — such as lists — then the values that they hold might change, but they continue to retain their identities.
Lists and Tuples
We have seen the close kinship between lists and tuples. Here is a brief summary that highlights the points of agreement and disagreement:
List | Tuple |
---|---|
Mutable | Immutable |
L = [1, 2, 3] |
T = (1, 2, 3) |
Supports indexing and slicing | Supports indexing and slicing |
Supports item assignment | Doesn't support item assignment |
Supported methods: count, index, append, insert, remove, pop and others |
Supported methods: count, index |
To get a list: list(obj) |
To get a tuple: tuple(obj) |
The partnership between lists and tuples is quite interesting and can be explored further with another example.
Populate a list that contains all ordered pairs of positive integers whose product is 100. Note that order matters: (2, 50) and (50, 2) are two different pairs.
Solution
pairs = [ ]
for a in range(1, 101):
for b in range(1, 101):
if a * b == 100:
pairs.append((a, b))
print(pairs)
pairs
is a list of tuples. We could have stored each pair as a list. But a tuple is the better choice here since the two elements in the pair have a well defined relationship and we don't want to accidentally modify them.
Packing and Unpacking
At first sight, tuples might seem redundant members in the Python family, but they do occupy a significant place. For that, we have to look at tuples in more detail. Consider the following code:
At first sight, line-1 seems to be an error. We have seen multiple assignment on the same line, perhaps we are two variables short on the LHS? But on execution, we see that there is no error. T
is in fact the tuple (1, 2, 3)
. This is called tuple packing. The values 1
, 2
and 3
are packed into a tuple. The reverse operation is called sequence unpacking:
Here, the tuple T
is unpacked into the corresponding variables x
, y
and z
. This is the principle behind multiple assignment. From the Python documentation, we have refer
Multiple assignment is a combination of tuple packing and sequence unpacking.
In the line given above, the RHS is first packed into a tuple and the sequence is then unpacked into the variables x
, y
and z
. But why does the unpacking operation have the qualifier sequence before it? This is because any sequence can be unpacked:
l1, l2, l3, l4 = 'good' # string
num1, num2, num3 = [1, 2, 3] # list
b1, b2 = (True, False) # tuple
x, y, z = range(3) # range
That's fun! The same operations are invoked when multiple values are returned from functions:
def max_min(a, b):
if a > b:
return a, b
return b, a
x = max_min(1, 2)
print(x)
print(isinstance(x, tuple))
We see that x
is a tuple. In the return statements at lines 3 and 4, multiple values are packed into tuples. So, the function is essentially returning a tuple.