Working with Tuples in Python
In the previous two lessons, we explained Python lists, which are container-type data types. Through list-type variables, we can save multiple data and implement batch operations on data through loops. Of course, Python has other container-type data types. Next, we’ll explain another container-type data type called tuple.
Tuple Definition and Operations
In Python, a tuple is also a sequence composed of multiple elements in a certain order. The difference between tuples and lists is that tuples are immutable types. This means that once a tuple-type variable is defined, its elements cannot be added or deleted, and element values cannot be modified. If you try to modify elements in a tuple, it will raise a TypeError error, causing the program to crash. Tuples are usually defined using literal syntax in the form (x, y, z). Tuple types support the same operators as lists. We can see the code below.
# Define a three-element tuple
t1 = (35, 12, 98)
# Define a four-element tuple
t2 = ('Luo Hao', 45, True, 'Chengdu, Sichuan')
# View variable type
print(type(t1)) # <class 'tuple'>
print(type(t2)) # <class 'tuple'>
# View number of elements in tuple
print(len(t1)) # 3
print(len(t2)) # 4
# Indexing operation
print(t1[0]) # 35
print(t1[2]) # 98
print(t2[-1]) # Chengdu, Sichuan
# Slicing operation
print(t2[:2]) # ('Luo Hao', 43)
print(t2[::3]) # ('Luo Hao', 'Chengdu, Sichuan')
# Loop through elements in tuple
for elem in t1:
print(elem)
# Membership operation
print(12 in t1) # True
print(99 in t1) # False
print('Hao' not in t2) # True
# Concatenation operation
t3 = t1 + t2
print(t3) # (35, 12, 98, 'Luo Hao', 43, True, 'Chengdu, Sichuan')
# Comparison operation
print(t1 == t3) # False
print(t1 >= t3) # False
print(t1 <= (35, 11, 99)) # False
If a tuple has two elements, we call it a two-tuple; if a tuple has five elements, we call it a five-tuple. It’s important to note that () represents an empty tuple, but if a tuple has only one element, you need to add a comma. Otherwise, () doesn’t represent tuple literal syntax but parentheses for changing operation priority. So ('hello', ) and (100, ) are one-tuples, while ('hello') and (100) are just strings and integers. We can verify this through the code below.
a = ()
print(type(a)) # <class 'tuple'>
b = ('hello')
print(type(b)) # <class 'str'>
c = (100)
print(type(c)) # <class 'int'>
d = ('hello', )
print(type(d)) # <class 'tuple'>
e = (100, )
print(type(e)) # <class 'tuple'>
Packing and Unpacking Operations
When we assign multiple comma-separated values to a variable, the multiple values are packed into a tuple type. When we assign a tuple to multiple variables, the tuple is unpacked into multiple values and then assigned to the corresponding variables, as shown in the code below.
# Packing operation
a = 1, 10, 100
print(type(a)) # <class 'tuple'>
print(a) # (1, 10, 100)
# Unpacking operation
i, j, k = a
print(i, j, k) # 1 10 100
During unpacking, if the number of unpacked elements doesn’t correspond to the number of variables, it will raise a ValueError exception with the error message: too many values to unpack (too many values to unpack) or not enough values to unpack (not enough values to unpack).
a = 1, 10, 100, 1000
# i, j, k = a # ValueError: too many values to unpack (expected 3)
# i, j, k, l, m, n = a # ValueError: not enough values to unpack (expected 6, got 4)
There’s a way to solve the problem when the number of variables is less than the number of elements, which is to use star expressions. Through star expressions, we can let one variable receive multiple values, as shown in the code below. Two things to note: first, variables modified with star expressions become lists with 0 or more elements; second, in unpacking syntax, star expressions can only appear once.
a = 1, 10, 100, 1000
i, j, *k = a
print(i, j, k) # 1 10 [100, 1000]
i, *j, k = a
print(i, j, k) # 1 [10, 100] 1000
*i, j, k = a
print(i, j, k) # [1, 10] 100 1000
*i, j = a
print(i, j) # [1, 10, 100] 1000
i, *j = a
print(i, j) # 1 [10, 100, 1000]
i, j, k, *l = a
print(i, j, k, l) # 1 10 100 [1000]
i, j, k, l, *m = a
print(i, j, k, l, m) # 1 10 100 1000 []
It should be noted that unpacking syntax works for all sequences. This means that the lists, range function-constructed range sequences, and even strings we discussed earlier can all use unpacking syntax. You can try running the code below to see what results appear.
a, b, *c = range(1, 10)
print(a, b, c)
a, b, c = [1, 10, 100]
print(a, b, c)
a, *b, c = 'hello'
print(a, b, c)
Swapping Variable Values
Swapping variable values is a frequently used operation when writing code. However, in many programming languages, swapping the values of two variables requires using an intermediate variable. If you don’t use an intermediate variable, you need to use rather obscure bitwise operations to implement it. In Python, swapping the values of two variables a and b only requires using the code shown below.
a, b = b, a
Similarly, if we want to swap the values of three variables a, b, c, i.e., assign the value of b to a, the value of c to b, and the value of a to c, we can do the same.
a, b, c = b, c, a
It should be noted that the operations above don’t use packing and unpacking syntax. Python’s bytecode instructions have instructions like ROT_TWO and ROT_THREE that can directly implement this operation with very high efficiency. However, if there are more than three variables whose values need to be swapped in sequence, there are no directly usable bytecode instructions. In this case, we need to complete the swapping of values between variables through packing and unpacking.
Comparing Tuples and Lists
Here’s a very worthwhile question to explore: Python already has list types, so why do we need tuple types? This question seems a bit difficult for beginners, but it doesn’t matter. We’ll first present our viewpoint, and everyone can gradually understand it while learning.
-
Tuples are immutable types. Immutable types are more suitable for multi-threaded environments because they reduce the synchronization overhead of concurrent access to variables. We’ll discuss this point with everyone when we explain concurrent programming later.
-
Tuples are immutable types. Usually, immutable types are superior to corresponding mutable types in creation time. We can use the
timeitfunction from thetimeitmodule to see how long it takes to create lists and tuples that save the same elements. Thenumberparameter of thetimeitfunction represents the number of times the code is executed. In the code below, we created lists and tuples that save integers from1to9, executing each operation10000000times and recording the running time.import timeit print('%.3f seconds' % timeit.timeit('[1, 2, 3, 4, 5, 6, 7, 8, 9]', number=10000000)) print('%.3f seconds' % timeit.timeit('(1, 2, 3, 4, 5, 6, 7, 8, 9)', number=10000000))Output:
0.635 seconds 0.078 secondsNote: The execution results of the code above vary depending on hardware and software systems. On the computer I’m currently using, executing the list creation operation
10000000times takes0.635seconds, while executing the tuple creation operation10000000times takes0.078seconds. Obviously, creating tuples is faster, and there’s an order of magnitude difference in time. You can execute this code on your own computer and post your execution results in the comments section to see whose computer is more powerful.
Of course, tuple and list types in Python can be converted to each other. We can complete this operation through the code below.
infos = ('Luo Hao', 43, True, 'Chengdu, Sichuan')
# Convert tuple to list
print(list(infos)) # ['Luo Hao', 43, True, 'Chengdu, Sichuan']
frts = ['apple', 'banana', 'orange']
# Convert list to tuple
print(tuple(frts)) # ('apple', 'banana', 'orange')
Summary
Both lists and tuples are container-type data types, meaning one variable can save multiple data, and they are both ordered containers that organize elements in a certain order. Lists are mutable data types, and tuples are immutable data types. So lists can add elements, delete elements, clear elements, sort and reverse, but these operations don’t apply to tuples. Both lists and tuples support concatenation operations, membership operations, indexing operations, slicing operations, etc. The string type we’ll discuss later also supports these operations because strings are sequences composed of characters in a certain order. In this respect, the three are no different. We recommend that everyone use list comprehension syntax to create lists. It’s not only easy to use but also very efficient, and it’s a very distinctive syntax feature of Python.