3.4. Python Tuples: Immutable Sequences in Python#
In Python, a tuple is a versatile and fundamental data structure that resembles a list in many ways, but with a crucial distinction: tuples are immutable. This immutability provides unique advantages, making tuples useful for various scenarios where data integrity, performance, and element order preservation are paramount. Understanding how to work with tuples effectively enhances your programming skills and equips you with a valuable tool for handling collections of items that should remain unchanged. In this section, we delve into the world of tuples, exploring their characteristics, use cases, and the benefits they bring to your Python programs [Downey, 2015, Python Software Foundation, 2023].
3.4.1. Tuple Operations#
3.4.1.1. Creating a Tuple#
In Python, a tuple is an ordered, immutable collection of elements. Tuples are created using parentheses ()
and can contain any data type, including other tuples. Once created, the elements of a tuple cannot be modified, added, or removed. Here’s how you can create a tuple:
Creating an empty tuple:
empty_tuple = ()
Creating a tuple with elements:
# Tuple with integers
my_tuple = (1, 2, 3)
# Tuple with mixed data types
mixed_tuple = (1, 'hello', 3.14)
# Tuple with nested tuples
nested_tuple = ((1, 2), ('a', 'b', 'c'), (True, False))
Using the
tuple()
constructor:
You can also create a tuple using the tuple()
constructor. If you pass an iterable (like a list or another tuple) as an argument to tuple()
, it will convert the iterable to a tuple.
my_list = [1, 2, 3]
tuple_from_list = tuple(my_list) # Converts the list to a tuple
print(tuple_from_list) # Output: (1, 2, 3)
(1, 2, 3)
Remember that tuples are immutable, so once you create a tuple, you cannot modify its elements. If you need a collection that can be modified, consider using a list instead.
3.4.1.2. Accessing Elements#
You can access individual elements of a tuple using indexing, just like lists. The index starts from 0 for the first element.
my_tuple = (10, 20, 30, 40, 50)
print(my_tuple[0]) # Output: 10
print(my_tuple[2]) # Output: 30
10
30
3.4.1.3. Tuple Slicing#
You can use slicing to extract a portion of a tuple.
my_tuple = (10, 20, 30, 40, 50)
print(my_tuple[1:4]) # Output: (20, 30, 40)
(20, 30, 40)
3.4.1.4. Tuple Length#
You can determine the length of a tuple using the len()
function.
my_tuple = (10, 20, 30, 40, 50)
print(len(my_tuple)) # Output: 5
5
3.4.1.5. Immutable Nature#
Once a tuple is created, you cannot change its elements. The following code will raise an error:
my_tuple = (1, 2, 3)
my_tuple[1] = 10 # This will raise a TypeError
3.4.1.6. Tuple Packing and Unpacking#
Tuple packing is the process of assigning multiple values to a single tuple, and tuple unpacking is the opposite operation of extracting values from a tuple into variables.
# Packing
my_tuple = 10, 20, 30 # Parentheses are optional
# Unpacking
a, b, c = my_tuple
print(a, b, c) # Output: 10 20 30
10 20 30
3.4.1.7. Single Element Tuple#
If you want to create a tuple with a single element, you need to include a comma after the element, as parentheses alone will not create a tuple with a single element.
single_element_tuple = (42,)
3.4.1.8. Tuple Addition and Multiplication#
Tuples support various operations like concatenation and repetition (using +
and *
, respectively).
tuple1 = (1, 2, 3)
tuple2 = (4, 5, 6)
# Concatenation
combined_tuple = tuple1 + tuple2 # Output: (1, 2, 3, 4, 5, 6)
print(combined_tuple)
# Repetition
repeated_tuple = tuple1 * 3 # Output: (1, 2, 3, 1, 2, 3, 1, 2, 3)
print(repeated_tuple)
(1, 2, 3, 4, 5, 6)
(1, 2, 3, 1, 2, 3, 1, 2, 3)
To find the maximum and minimum values of a tuple in Python, you can use the built-in max() and min() functions, respectively. These functions work with tuples just like they do with lists and other iterable objects. Here’s how you can use them:
my_tuple = (10, 30, 5, 40, 20)
# Maximum value in the tuple
max_value = max(my_tuple)
print("Maximum:", max_value) # Output: Maximum: 40
# Minimum value in the tuple
min_value = min(my_tuple)
print("Minimum:", min_value) # Output: Minimum: 5
Maximum: 40
Minimum: 5
3.4.1.9. Sorting Tupbles#
Returns a new sorted list (not a tuple) from the elements of the tuple.
my_tuple = (5, 3, 1, 4, 2)
sorted_list = sorted(my_tuple)
print(sorted_list) # Output: [1, 2, 3, 4, 5]
sorted_list = sorted(my_tuple, reverse = True)
print(sorted_list) # Output: [5, 4, 3, 2, 1]
[1, 2, 3, 4, 5]
[5, 4, 3, 2, 1]
3.4.1.10. Tuple Count Method#
The tuple count method is a fundamental operation in Python used to determine the number of occurrences of a specified element within a tuple. This method is applied to a tuple and takes one argument, which is the element you want to count. It then returns the count of that element within the tuple.
Here is the basic syntax for the tuple count method:
tuple.count(element)
tuple
: This is the tuple on which you want to perform the counting operation.element
: This is the element you want to count within the tuple.
The method returns an integer representing the count of occurrences of the specified element in the tuple. If the element is not found in the tuple, it returns 0.
Example: Here’s an example of how to use the tuple count method in Python:
# Define a tuple with integer elements
my_tuple = (1, 2, 2, 3, 4, 2, 5)
# Use the tuple count method to count the occurrences of the element 2
count_of_twos = my_tuple.count(2)
# Print the result, indicating the count of twos in the tuple
print("Count of twos in the tuple:", count_of_twos)
Count of twos in the tuple: 3
In this example, the count_of_twos
variable will contain the value 3, as there are three occurrences of the element 2 in the my_tuple
.
3.4.2. Iterating Over a Tuple#
You can use loops to iterate over the elements of a tuple.
my_tuple = (10, 20, 30)
for element in my_tuple:
print(element)
10
20
30
Tuples are useful when you have a collection of elements that should not change throughout the program’s execution. They are commonly used for functions that return multiple values and in situations where you want to ensure data integrity and prevent accidental modification.
3.4.3. Using the index()
Method with Tuples#
The index()
method allows you to locate the index (position) of the first occurrence of a specified item within a tuple. It takes the item you want to find as an argument and returns its index.
Example: Finding the index of an item in a tuple.
my_tuple = (10, 20, 30, 40, 50)
# Find the index of the item 30 in the tuple
index = my_tuple.index(30)
# Print the result
print(f"The index of 30 is {index}") # Output: The index of 30 is 2
The index of 30 is 2
In this example, we have a tuple my_tuple
containing integers. We use the index()
method to find the index of the item 30
, which is at index 2
in the tuple.
Example: Handling items not found in the tuple.
my_tuple = (10, 20, 30, 40, 50)
# Try to find the index of the item 60 in the tuple
try:
index = my_tuple.index(60)
print(f"The index of 60 is {index}")
except ValueError:
print("Item not found in the tuple")
# Output: Item not found in the tuple
Item not found in the tuple
In this example, we attempt to find the index of the item 60
, which is not present in the tuple. Since it’s not found, the index()
method raises a ValueError
exception, which we catch and handle with a message indicating that the item was not found in the tuple.
These examples illustrate how to use the index()
method with tuples to find the index of a specific item and how to handle cases where the item is not present in the tuple.
3.4.4. Lists and tuples#
3.4.4.1. Using enumerate
for Index-Element Pairs#
The enumerate
function is another useful built-in function that returns an enumerate object. It iterates through pairs containing the index and the element from the sequence:
for index, element in enumerate('abc'):
print(index, element)
0 a
1 b
2 c
In this code:
enumerate('abc')
: Theenumerate()
function is used to iterate through the characters of the string'abc'
. It pairs each character with its corresponding index in the string. The result ofenumerate('abc')
is an iterable that yields pairs of(index, element)
.for index, element in ...
: This line initiates afor
loop to iterate through the pairs produced byenumerate('abc')
. In each iteration,index
will represent the index of the character, andelement
will represent the character itself.print(index, element)
: Inside the loop, this line prints theindex
followed by theelement
for each character in the string. As the loop iterates, it prints both the index and the character.
3.4.4.2. Traversing Two Sequences Simultaneously#
A common use case for zip
is to traverse two or more sequences simultaneously in a for
loop using tuple assignment:
t = [('a', 0), ('b', 1), ('c', 2)]
for letter, number in t:
print(number, letter)
0 a
1 b
2 c
Let’s explain the code step by step:
t = [('a', 0), ('b', 1), ('c', 2)]
: This line initializes a listt
containing tuples. Each tuple consists of two elements: a letter (string) and a number (integer). For example,('a', 0)
pairs the letter ‘a’ with the number 0, and so on.for letter, number in t:
: This line sets up afor
loop to iterate through the tuples within the listt
. The loop uses tuple unpacking, where each tuple is unpacked into the variablesletter
andnumber
, corresponding to the elements in each tuple.print(number, letter)
: Inside the loop, this line prints thenumber
followed by theletter
for each tuple. As the loop iterates throught
, it prints the number-letter pairs in the specified order.
3.4.4.3. zip
Function in Python#
zip
is a versatile built-in function in Python that takes two or more sequences, like lists, tuples, or strings, and combines them element-wise to create a zip object. The name “zip” comes from the concept of a zipper, where two rows of teeth interlock together [Downey, 2015, Python Software Foundation, 2023].
Usage:
zip_obj = zip(sequence1, sequence2, ...)
Example:
s = 'abc'
t = [0, 1, 2]
# Use the zip() function to create an iterator that combines elements from 's' and 't'
zip_result = zip(s, t)
# Print the result, which is a zip object
print(zip_result) # Output: <zip object at 0x***********>
<zip object at 0x000002A179CFFA80>
Let’s explain the code step by step:
s = 'abc'
: This line defines a strings
containing the characters ‘a’, ‘b’, and ‘c’.t = [0, 1, 2]
: Here, we create a listt
containing integers 0, 1, and 2.zip_result = zip(s, t)
: Thezip()
function is used to create an iterator that combines elements from boths
andt
. It pairs elements at corresponding positions, resulting in an iterable zip object.print(zip_result)
: Finally, we print thezip_result
, which is a zip object.# Output: <zip object at 0x***********>
: This comment indicates the expected output, showing thatzip_result
is a zip object located at a specific memory address.
3.4.4.4. Iterating through a Zip Object#
The most common use of zip
is in a for
loop to iterate through the pairs:
s = 'abc'
t = [0, 1, 2]
for pair in zip(s, t):
print(pair)
('a', 0)
('b', 1)
('c', 2)
Let’s explain the code step by step:
for pair in zip(s, t):
: This line initiates a loop that iterates through pairs of elements created by thezip()
function. Each pair consists of one element from the strings
and one element from the listt
.print(pair)
: Inside the loop, we print each pair of elements. This will display the combined elements froms
andt
at their corresponding positions.
The loop effectively combines elements from s
and t
and prints them one pair at a time.
3.4.4.5. Converting Zip Object to a List#
If you want to work with the elements as a list, you can convert the zip object to a list using the list()
function:
zip_list = list(zip(s, t))
print(zip_list) # Output: [('a', 0), ('b', 1), ('c', 2)]
[('a', 0), ('b', 1), ('c', 2)]
3.4.4.6. Handling Different Length Sequences#
If the input sequences are of different lengths, zip
will stop creating pairs when it reaches the end of the shorter sequence:
result = list(zip('Anne', 'Elk'))
print(result) # Output: [('A', 'E'), ('n', 'l'), ('n', 'k')]
[('A', 'E'), ('n', 'l'), ('n', 'k')]
Let’s explain the code step by step:
zip('Anne', 'Elk')
: In this line, thezip()
function is used to combine two sequences: the string'Anne'
and the string'Elk'
. It pairs the characters at corresponding positions, creating tuples of characters. Here’s how the pairing happens:First pair: (‘A’, ‘E’) - The first character of
'Anne'
(‘A’) is paired with the first character of'Elk'
(‘E’).Second pair: (‘n’, ‘l’) - The second character of
'Anne'
(‘n’) is paired with the second character of'Elk'
(‘l’).Third pair: (‘n’, ‘k’) - The third character of
'Anne'
(‘n’) is paired with the third character of'Elk'
(‘k’).
list(zip('Anne', 'Elk'))
: Here, thezip
object created in the previous step is converted into a list using thelist()
function. This results in a list of tuples, where each tuple represents a pair of characters from the original strings.print(result)
: Finally, this line prints theresult
, which is the list of tuples created by zipping the characters from the two strings.# Output: [('A', 'E'), ('n', 'l'), ('n', 'k')]
: This comment indicates the expected output. It shows that theresult
list contains three tuples, each representing a pair of characters from the strings'Anne'
and'Elk'
.
3.4.4.7. Using zip
for Matching Elements#
You can use zip
to check for matching elements in two sequences:
def has_match(t1, t2):
# Iterate through corresponding elements of t1 and t2 using zip
for x, y in zip(t1, t2):
if x == y: # Check if the elements at the current positions are equal
return True # If a match is found, return True
return False # If no match is found after the loop, return False
Let’s explain the code step by step:
def has_match(t1, t2):
: This line defines a function calledhas_match
that takes two sequences,t1
andt2
, as input.for x, y in zip(t1, t2):
: Inside the function, afor
loop is used to iterate through corresponding elements oft1
andt2
using thezip()
function. It pairs elements at the same positions in both sequences.if x == y:
: Within the loop, this condition checks if the elements at the current positions (x
fromt1
andy
fromt2
) are equal.return True
: If a match is found (i.e.,x
andy
are equal), the function immediately returnsTrue
.return False
: If no match is found after the loop has checked all corresponding elements, the function returnsFalse
.
This function is designed to determine whether there is at least one matching pair of elements at the same positions in t1
and t2
. If such a match exists, the function returns True
; otherwise, it returns False
.
3.4.5. Dictionaries and tuples#
Dictionaries in Python have a method called items()
that returns a sequence of tuples, where each tuple represents a key-value pair in the dictionary. Let’s go through the examples and concepts related to dictionaries and tuples [Downey, 2015, Python Software Foundation, 2023]:
3.4.5.1. Using items()
method:#
The items()
method returns a dict_items
object, which is an iterator over the key-value pairs of the dictionary. The order of items in the dict_items
object is not guaranteed to be the same as the order of insertion in the dictionary.
3.4.5.2. Iterating through dictionary items:#
You can use the items()
method in a for
loop to iterate through the key-value pairs of the dictionary. In the example provided, the dictionary d
contains key-value pairs ‘a’: 0, ‘b’: 1, and ‘c’: 2. When we iterate through d.items()
, the output shows the key-value pairs in no particular order.
# Creating a dictionary
d = {'a': 0, 'b': 1, 'c': 2}
# Using items() to get key-value pairs as tuples
t = d.items()
print(t) # Output: dict_items([('c', 2), ('a', 0), ('b', 1)])
# Iterating through dictionary items
for key, value in d.items():
print(key, value)
dict_items([('a', 0), ('b', 1), ('c', 2)])
a 0
b 1
c 2
3.4.5.3. Creating a dictionary from a list of tuples:#
You can initialize a new dictionary by passing a list of tuples to the dict()
function. Each tuple in the list contains a key-value pair. The example demonstrates how a list of tuples t
can be used to create a new dictionary d
.
# A list of tuples representing key-value pairs
t = [('a', 0), ('c', 2), ('b', 1)]
# Creating a dictionary from the list of tuples
d = dict(t)
print(d) # Output: {'a': 0, 'c': 2, 'b': 1}
{'a': 0, 'c': 2, 'b': 1}
3.4.5.4. Creating a dictionary with zip
:#
By combining dict()
with zip()
, you can create a dictionary in a concise manner. The zip()
function combines two sequences (e.g., strings or lists) element-wise, and then dict()
converts these pairs into a dictionary, with the elements from the first sequence as keys and the elements from the second sequence as values.
# Using zip to combine two sequences into pairs
keys = 'abc'
values = range(3)
d = dict(zip(keys, values))
print(d) # Output: {'a': 0, 'c': 2, 'b': 1}
{'a': 0, 'b': 1, 'c': 2}
3.4.5.5. Using tuples as keys in dictionaries:#
Tuples can be used as keys in dictionaries, while lists cannot be used as keys because they are mutable. This is useful when you need to create a mapping between multiple values, such as in the case of a telephone directory where last-name, first-name pairs are mapped to telephone numbers.
# Telephone directory mapping last-name, first-name pairs to telephone numbers
directory = {}
directory['Doe', 'John'] = '123-456-7890'
directory['Smith', 'Alice'] = '987-654-3210'
# Accessing telephone numbers using tuple keys
print(directory['Doe', 'John']) # Output: 123-456-7890
print(directory['Smith', 'Alice']) # Output: 987-654-3210
123-456-7890
987-654-3210
3.4.5.6. Traversing a dictionary with tuple assignment:#
Traversing a dictionary with tuple assignment allows you to access and work with the individual elements of tuple keys. This can be particularly useful when you have a dictionary with tuples as keys and you want to perform operations on each element of the tuple. Here’s an example:
# Assume we have a dictionary with tuple keys and some corresponding values
grades = {('Alice', 'Smith'): 90,
('Bob', 'Johnson'): 85,
('John', 'Doe'): 78,
('Emma', 'Brown'): 92
}
# Traversing the dictionary using tuple assignment
for first, last in grades:
print(f"{first} {last} has a grade of {grades[first, last]}")
Alice Smith has a grade of 90
Bob Johnson has a grade of 85
John Doe has a grade of 78
Emma Brown has a grade of 92
In this example, the grades
dictionary has tuples containing first names and last names as keys, and integer grades as values. By using tuple assignment in the for
loop, we can access each element of the tuple key (first
and last
) separately and use them to display the name and grade information.
Another Example:
# Assume we have a telephone directory with multiple entries
directory = {('Doe', 'John'): '123-456-7890',
('Smith', 'Alice'): '987-654-3210',
('Johnson', 'Bob'): '111-222-3333'
}
# Traversing the dictionary with tuple assignment
for last, first in directory:
print(first, last, directory[last, first])
John Doe 123-456-7890
Alice Smith 987-654-3210
Bob Johnson 111-222-3333
3.4.6. Sequences of sequences#
In Python, “sequences of sequences” refers to data structures where elements within the sequences are also sequences themselves. This can be achieved using different data structures, such as lists, tuples, or strings. Here, we’ll explore some examples of sequences of sequences [Downey, 2015, Python Software Foundation, 2023]:
3.4.6.1. List of Lists#
# List of lists, where each inner list represents a row in a matrix
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Accessing individual elements in the matrix
print(matrix[0][0]) # Output: 1
print(matrix[1][2]) # Output: 6
1
6
3.4.6.2. List of Tuples#
# List of tuples representing points in a 2D plane
points = [(0, 0),(1, 2),(3, 5),(-1, 4)]
# Accessing individual elements in the tuples
print(points[1][0]) # Output: 1
print(points[2][1]) # Output: 5
1
5
3.4.6.3. Tuple of Lists#
# Tuple containing multiple lists
data = ([1, 2, 3], [4, 5, 6], [7, 8, 9])
# Accessing individual elements in the lists
print(data[0][1]) # Output: 2
print(data[2][0]) # Output: 7
2
7
3.4.6.4. List of Strings#
# List of strings
words = ["apple", "banana", "cherry"]
# Accessing individual characters in the strings
print(words[0][1]) # Output: 'p'
print(words[2][4]) # Output: 'r'
p
r
Sequences of sequences are widely used in various scenarios, such as representing matrices, collections of points, datasets, etc. They provide a convenient way to organize related data and enable hierarchical access to individual elements within the nested sequences.
3.4.7. Named Tuples#
Named tuples in Python are a convenient way to define lightweight classes for storing simple data structures. They provide a way to create simple classes that don’t require the full features of a custom class definition. Named tuples are essentially like regular tuples, but with named fields, making the code more readable and self-documenting.
Here’s how you can use named tuples in Python:
from collections import namedtuple
# Define a named tuple type
Person = namedtuple("Person", ["name", "age", "city"])
# Create instances of the named tuple
person1 = Person(name="Alice", age=30, city="New York")
person2 = Person(name="Bob", age=25, city="San Francisco")
# Access fields using dot notation
print(person1.name) # Output: Alice
print(person2.age) # Output: 25
# Named tuples are immutable
# person1.name = "Eve" # This will raise an AttributeError
Alice
25
In the example above, we first import namedtuple
from the collections
module. Then, we define a named tuple type called “Person” with three fields: “name”, “age”, and “city”. We create instances of this named tuple by specifying values for each field. We can access the fields of the named tuple using dot notation, making the code more readable.
It’s important to note that named tuples are immutable, meaning you can’t modify the values of the fields after creating an instance. If you need to modify the data, you’ll need to create a new named tuple with the desired changes.
Named tuples are useful when you need a simple and readable way to represent data structures, such as when dealing with records, configurations, or other situations where you have a fixed set of fields.