A tuple is an immutable sequence of values:
xxxxxxxxxx
31family = ('father', 'mother', 'child')
2print(type(family))
3print(isinstance(family, tuple))
Tuples share a close resemblance to lists. They can be indexed and sliced just like lists:
xxxxxxxxxx
21print(family[0])
2print(family[:2])
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:
xxxxxxxxxx
41##### Alarm! Wrong code snippet! #####
2numbers = ('one', 'two', 'four')
3numbers[2] = 'three'
4##### 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:
xxxxxxxxxx
31numbers = (1, 2, 3, 1, 1)
2print(numbers.count(1))
3print(numbers.index(2))
We can iterate through a tuple using for
:
xxxxxxxxxx
21for num in (1, 2, 3):
2 print(num)
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.
A few more points on tuples.
xxxxxxxxxx
31i_am_single = (1, )
2print(len(i_am_single))
3print(isinstance(i_am_single, tuple))
Note the presence of a comma after the element. Let us see what happens if it is removed:
xxxxxxxxxx
21i_am_single = (1)
2print(isinstance(i_am_single, int))
It is an integer!
xxxxxxxxxx
41a_list = [1, 2, 3]
2a_tuple = tuple(a_list)
3b_tuple = (1, 2, 3)
4b_list = list(b_tuple)
xxxxxxxxxx
11a_tuple = (1, 'cool', True)
in
keyword:xxxxxxxxxx
211 in (1, 2, 3)
2'hello' not in ('some', 'random', 'sequence')
xxxxxxxxxx
21a = ((1, 2, 3), (4, 5, 6))
2print(a[0][2])
xxxxxxxxxx
21a_tuple = ([0, 1, 2], [4, 5, 6])
2a_tuple[0][0] = 100
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:
xxxxxxxxxx
41a_tuple = ([0, 1, 2], [4, 5, 6])
2print(id(a_tuple[0]))
3a_tuple[0][0] = 100
4print(id(a_tuple[0]))
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.
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
xxxxxxxxxx
61pairs = [ ]
2for a in range(1, 101):
3 for b in range(1, 101):
4 if a * b == 100:
5 pairs.append((a, b))
6print(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.
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:
xxxxxxxxxx
31T = 1, 2, 3
2print(T)
3print(isinstance(T, tuple))
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:
xxxxxxxxxx
21x, y, z = T
2print(x, y, z)
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.
xxxxxxxxxx
11x, y, z = 1, 2, 3
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:
xxxxxxxxxx
41l1, l2, l3, l4 = 'good' # string
2num1, num2, num3 = [1, 2, 3] # list
3b1, b2 = (True, False) # tuple
4x, y, z = range(3) # range
That's fun! The same operations are invoked when multiple values are returned from functions:
xxxxxxxxxx
81def max_min(a, b):
2 if a > b:
3 return a, b
4 return b, a
5
6x = max_min(1, 2)
7print(x)
8print(isinstance(x, tuple))
We see that x
is a tuple. In the return statements at lines 3 and 4, the multiple values are packed into tuples. So, the function is essentially returning a tuple.