Перейти к содержимому
Editor

Кортежи в Python: зачем нужны неизменяемые последовательности

Начальный20 min5 упр.60 XP

Этот урок переведён с английского оригинала.Read in EnglishLeer en españolСообщить об ошибке в переводе

0/5 упр.

Вспомните GPS-координаты. Точка (40.7128, -74.0060) обозначает Нью-Йорк. Если случайно изменить одно из этих чисел, точка окажется совсем в другом месте. Некоторые данные не должны меняться после того, как вы их создали.

С датами то же самое. 1 января 2025 года остаётся неизменным фактом. Вам вряд ли захочется, чтобы код случайно превратил эту дату в 37 февраля. Когда данные должны оставаться неизменными, Python предлагает кортежи.

Кортеж выглядит почти так же, как список, но с одним важнейшим отличием: созданный кортеж нельзя изменить. Нельзя добавить элемент, удалить его или заменить. В этом уроке вы узнаете, почему это ограничение на самом деле оказывается суперсилой.

Как создать кортеж в Python

Кортеж создают, перечисляя элементы через запятую внутри круглых скобок (). Можно создать кортеж и без скобок: кортежем его делают именно запятые.

Создание кортежей
# Tuple with parentheses
coordinates = (40.7128, -74.0060)
print(coordinates)
# Tuple without parentheses (commas do the work)
colors = 'red', 'green', 'blue'
print(colors)
# Single-item tuple NEEDS a trailing comma
single = (42,)
print(single) # (42,)
print(type(single)) # <class 'tuple'>
Вывод
(40.7128, -74.006)
('red', 'green', 'blue')
(42,)
<class 'tuple'>
Кортеж из одного элемента и выражение в скобках
# This is NOT a tuple
not_a_tuple = (42)
print(type(not_a_tuple)) # <class 'int'>
# This IS a tuple
is_a_tuple = (42,)
print(type(is_a_tuple)) # <class 'tuple'>
# Empty tuple
empty = ()
print(empty) # ()
print(len(empty)) # 0
Вывод
<class 'int'>
<class 'tuple'>
()
0

Другие последовательности тоже можно превратить в кортеж с помощью конструктора tuple(). Это удобно, когда у вас есть список и его нужно «заморозить», чтобы никто не мог его изменить.

Конструктор tuple()
# Convert a list to a tuple
fruit_list = ['apple', 'banana', 'cherry']
fruit_tuple = tuple(fruit_list)
print(fruit_tuple) # ('apple', 'banana', 'cherry')
# Convert a string to a tuple of characters
letters = tuple('hello')
print(letters) # ('h', 'e', 'l', 'l', 'o')
Вывод
('apple', 'banana', 'cherry')
('h', 'e', 'l', 'l', 'o')

Доступ к элементам кортежа и срезы

Доступ к элементам кортежа устроен точно так же, как у списков. Индекс указывается в квадратных скобках. Положительные индексы отсчитываются с начала, отрицательные с конца.

Индексы в кортежах
months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun')
# Positive indexing
print(months[0]) # Jan
print(months[3]) # Apr
# Negative indexing
print(months[-1]) # Jun
print(months[-2]) # May
# Length
print(len(months)) # 6
Вывод
Jan
Apr
Jun
May
6

Срезы работают так же. Часть кортежа можно получить с помощью tuple[start:end]. Результатом будет новый кортеж.

Срезы кортежей
months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun')
# Slice from index 1 to 4 (not including 4)
print(months[1:4]) # ('Feb', 'Mar', 'Apr')
# First three
print(months[:3]) # ('Jan', 'Feb', 'Mar')
# Last two
print(months[-2:]) # ('May', 'Jun')
# Every other month
print(months[::2]) # ('Jan', 'Mar', 'May')
Вывод
('Feb', 'Mar', 'Apr')
('Jan', 'Feb', 'Mar')
('May', 'Jun')
('Jan', 'Mar', 'May')

А вот здесь кортежи отличаются от списков. Если попытаться изменить элемент, Python выбросит TypeError. Кортежи неизменяемые: после создания их нельзя изменить.

Кортежи неизменяемы
colors = ('red', 'green', 'blue')
# This works fine - reading
print(colors[0]) # red
# This will CRASH - writing
# colors[0] = 'yellow' # TypeError: 'tuple' object does not support item assignment
# Uncomment the line above and run it to see the error!
Вывод
red

Упаковка и распаковка кортежей

Упаковка происходит, когда вы создаёте кортеж, присваивая одной переменной несколько значений. Распаковка работает наоборот: значения извлекаются из кортежа в отдельные переменные. Распаковка относится к самым полезным возможностям Python.

Упаковка и распаковка
# Packing - multiple values into one tuple
person = 'Alice', 25, 'Engineer'
print(person) # ('Alice', 25, 'Engineer')
# Unpacking - one tuple into multiple variables
name, age, job = person
print(name) # Alice
print(age) # 25
print(job) # Engineer
Вывод
('Alice', 25, 'Engineer')
Alice
25
Engineer

Количество переменных слева должно совпадать с количеством элементов кортежа. Если они не совпадают, Python выбрасывает ValueError.

Классический пример распаковки: обмен значений двух переменных без временной переменной. В большинстве других языков для этого нужны три строки, а Python справляется в одну.

Обмен значений через распаковку кортежа
a = 10
b = 20
print(f'Before: a={a}, b={b}')
# Swap using tuple unpacking
a, b = b, a
print(f'After: a={a}, b={b}')
Вывод
Before: a=10, b=20
After:  a=20, b=10

При распаковке можно поставить звёздочку *, чтобы собрать оставшиеся элементы. Это называется расширенной распаковкой, и в результате вы получаете список из оставшихся элементов.

Расширенная распаковка с оператором «звёздочка»
scores = (95, 87, 72, 68, 91)
# Grab the first, last, and everything in between
first, *middle, last = scores
print(first) # 95
print(middle) # [87, 72, 68]
print(last) # 91
Вывод
95
[87, 72, 68]
91
Распаковка кортежей в цикле for
students = [
('Alice', 95),
('Bob', 87),
('Charlie', 72),
]
for name, score in students:
print(f'{name} scored {score}')
Вывод
Alice scored 95
Bob scored 87
Charlie scored 72

Кортежи и списки: когда что использовать

Если кортежи всего лишь списки, которые нельзя менять, зачем они вообще нужны? Есть три веские причины: безопасность, производительность и ясность.

Безопасность: когда данные не должны меняться, кортеж защищает их от случайных изменений. GPS-координаты, цвета RGB, записи из базы данных относятся к неизменным фактам. Кортеж ясно показывает ваше намерение.

Производительность: кортежи немного быстрее списков и занимают меньше памяти. Для маленьких коллекций это почти незаметно, но на миллионах записей разница накапливается.

Ключи словаря: кортежи можно использовать как ключи словаря, потому что они неизменяемы. Списки так использовать нельзя. Это станет важно, когда вы начнёте изучать словари.

Используйте список, когда...
# Data that changes over time
shopping = ['milk', 'eggs']
shopping.append('bread')

# Collections you sort or filter
scores = [85, 92, 78]
scores.sort()
Используйте кортеж, когда...
# Fixed data that shouldn't change
coords = (40.7128, -74.0060)
rgb_red = (255, 0, 0)

# Returning multiple values
def get_name_age():
    return 'Alice', 25

Под капотом: почему кортежи быстрее списков

Поскольку кортежи неизменяемы, Python может незаметно применять к ним оптимизации. Размер кортежа фиксируется при создании, поэтому Python не нужно выделять лишнюю память на возможный рост, как он делает это для списков.

Сравниваем расход памяти
import sys
# Compare memory usage
my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
print(f'List size: {sys.getsizeof(my_list)} bytes')
print(f'Tuple size: {sys.getsizeof(my_tuple)} bytes')
Вывод
List size:  52 bytes
Tuple size: 40 bytes

Кортежи поддерживают и все операции, которые не изменяют последовательность. count() считает, сколько раз встречается значение, index() находит позицию значения, in проверяет, есть ли элемент в кортеже, а + склеивает кортежи.

Методы и операции кортежей
numbers = (1, 2, 3, 2, 4, 2)
# count() - how many times a value appears
print(numbers.count(2)) # 3
# index() - position of first occurrence
print(numbers.index(3)) # 2
# in - membership check
print(4 in numbers) # True
# Concatenation creates a NEW tuple
combined = (1, 2) + (3, 4)
print(combined) # (1, 2, 3, 4)
Вывод
3
2
True
(1, 2, 3, 4)

Практические упражнения

Пора попрактиковаться! Эти упражнения посвящены созданию кортежей, распаковке и пониманию неизменяемости.

Упражнение 1: создайте кортеж и получите элементы
Напишите код

Создайте кортеж seasons из четырёх времён года в виде строк: 'Spring', 'Summer', 'Fall', 'Winter'.

Затем выведите первое и последнее время года, каждое на отдельной строке.

Ожидаемый вывод:

Spring
Winter
# Create the seasons tuple
# Print the first season
# Print the last season
Упражнение 2: предскажите вывод (кортеж из одного элемента)
Угадайте вывод

Внимательно прочитайте этот код. Что он выведет? Подумайте, что делает значение кортежем, а что оставляет его обычным числом в скобках.

Впишите вывод в точности.

a = (5)
b = (5,)
print(type(a).__name__)
print(type(b).__name__)
Упражнение 3: распакуйте кортеж
Напишите код

Дан кортеж с данными об ученике. Распакуйте его в три переменные: name, age и grade.

Затем выведите каждую переменную на отдельной строке.

Ожидаемый вывод:

Emma
16
A
student = ('Emma', 16, 'A')
# Unpack the tuple into name, age, grade
# Print each variable
Упражнение 4: исправьте попытку изменить кортеж
Исправьте ошибку

Этот код пытается заменить цвет в кортеже, но кортежи неизменяемы. Исправьте его так, чтобы программа выводила обновлённые цвета, не изменяя исходный кортеж. Вместо этого создайте новый кортеж.

Ожидаемый вывод:

('red', 'yellow', 'blue')
colors = ('red', 'green', 'blue')
colors[1] = 'yellow'
print(colors)
Упражнение 5: перебор и распаковка баллов учеников
Напишите код

Есть список кортежей, в каждом кортеже имя ученика и его балл. Переберите список, распакуйте каждый кортеж и выведите результат каждого ученика в таком формате:

Alice: 92
Bob: 85
Charlie: 78
students = [
('Alice', 92),
('Bob', 85),
('Charlie', 78),
]
# Loop through and print each student's result

Итоги: что вы узнали о кортежах в Python

Повторим всё, что вы теперь знаете о кортежах:

ПонятиеЧто делаетПример
Создание кортежаХранит неизменный набор элементовpoint = (3, 4)
Запятая в концеСоздаёт кортеж из одного элементаsolo = (42,)
ИндексыДоступ по позицииpoint[0], point[-1]
СрезыПолучение частиmonths[1:4]
РаспаковкаИзвлечение в переменныеx, y = point
Расширенная распаковкаСобирает оставшиеся элементы через *first, *rest = items
count()Считает вхожденияt.count(2)
index()Находит позициюt.index(3)
НеизменяемостьНельзя изменить после созданияВыбрасывает TypeError

Кортежи идеально подходят для неизменных наборов данных: координат, цветов, записей и значений, которые возвращают функции. Благодаря неизменяемости код становится надёжнее, а ваши намерения понятнее.

Что дальше?

В следующем уроке, [Словари в Python](/python/python-dictionaries), вы научитесь хранить данные в виде пар «ключ: значение». Вместо доступа к элементам по позиции вы будете обращаться к ним по имени.

Словари относятся к самым мощным структурам данных в Python. Вместе со списками и кортежами они позволяют описать почти любые данные из реальной жизни.

Похожие уроки

Урок был полезен?