Примеры идут от базовых свойств кортежа (создание, неизменяемость, операции) к прикладным задачам практикума и домашнего задания. Урок разбирает не одну задачу, а полную картину темы — вместе с ограничением source «не используйте неизученные коллекции», которое объясняет, почему уникальность и фильтрация здесь собираются вручную, а не через set(). Весь вывод в комментариях получен запуском кода.
Пример 1. Создание кортежей и неизменяемость
Ключевой признак кортежа — запятая, а не скобки. Скобки нужны только для наглядности и группировки.
many_values = (1, 2, 3, "apple", True)
empty_tuple = ()
single_value = (5,)
not_a_tuple = (5) # это просто число в скобках
packed_tuple = 1, 2, 3 # скобки вообще не обязательны
print(many_values)
print(empty_tuple)
print(single_value, type(single_value)) # (5,) <class 'tuple'>
print(not_a_tuple, type(not_a_tuple)) # 5 <class 'int'>
print(packed_tuple, type(packed_tuple)) # (1, 2, 3) <class 'tuple'>
numbers = (10, 20, 30)
try:
numbers[1] = 40
except TypeError as error:
print("TypeError:", error)
# 'tuple' object does not support item assignment
updated_numbers = numbers[:1] + (40,) + numbers[2:]
print(updated_numbers) # (10, 40, 30) — не изменили, а собрали новый кортеж
Что происходит: запятая — единственное, что делает выражение кортежем; скобки — просто визуальная подсказка (кроме пустого (), где скобки обязательны). Изменить элемент по индексу нельзя в принципе — вместо этого через срезы и + собирается новый кортеж с нужным значением.
Пример 2. Операции с кортежами и преобразование в список
Многие операции у кортежа такие же, как у списков и строк: сложение, повторение, проверка наличия, длина, поэлементное сравнение.
tuple1 = (1, 2)
tuple2 = (3, 4)
print(tuple1 + tuple2) # (1, 2, 3, 4)
print(tuple1 * 3) # (1, 2, 1, 2, 1, 2)
print(2 in tuple1) # True
print(len(tuple1)) # 2
print((1, 2, 3) == (1, 2, 4)) # False — сравнение поэлементное
values = [1, 2, 3]
as_tuple = tuple(values)
as_list = list(as_tuple)
print(as_tuple, type(as_tuple)) # (1, 2, 3) <class 'tuple'>
print(as_list, type(as_list)) # [1, 2, 3] <class 'list'>
Почему так: tuple() и list() — не «превращение» одного объекта в другой, а создание нового объекта нужного типа из содержимого исходного. Переключаются между ними именно тогда, когда нужно один раз изменить данные (list()), а затем снова зафиксировать результат (tuple()).
Пример 3. Карточка пользователя: распаковка в именованные переменные
user = ("Alice", 29, "Python")
name, age, language = user
print(f"Имя: {name}")
print(f"Возраст: {age}")
print(f"Язык: {language}")
Кортеж хорошо подходит, когда структура небольшая и фиксированная: имя, возраст, язык — три значения, три переменные, порядок задан один раз при создании.
Пример 4. Перебор: for, распаковка пар, enumerate()
Кортеж — итерируемый объект, поэтому его перебирают так же, как список или строку. Если элементы сами являются кортежами (парами), их можно распаковать прямо в заголовке цикла.
scores = (10, 20, 30, 40)
for score in scores:
print(score)
pairs = ((1, "apple"), (2, "banana"), (3, "cherry"))
for number, fruit in pairs:
print(f"Число: {number}, Фрукт: {fruit}")
languages = ("Python", "Java", "C++")
for index, language in enumerate(languages, start=1):
print(f"{index}: {language}")
print(tuple(enumerate(languages)))
# ((0, 'Python'), (1, 'Java'), (2, 'C++')) — enumerate сам по себе не печатается как список пар
Что важно: enumerate(languages, start=1) нумерует элементы с единицы для вывода, но сам объект enumerate внутри всегда считает с нуля — это видно, если обернуть его в tuple() без start.
Пример 5. Уникальные элементы без неизученных коллекций
numbers = (1, 2, 3, 2, 1, 4, 5, 3, 6)
unique_numbers = tuple()
for number in numbers:
if number not in unique_numbers:
unique_numbers += (number,)
print("Уникальные элементы:", unique_numbers)
Это решение следует ограничению из исходного задания: не использовать неизученные коллекции (set появится позже, в уроке 32, и решит ту же задачу короче).
Пример 6. Элементы выше среднего
numbers = (10, 15, 20, 25, 30)
average = sum(numbers) / len(numbers)
greater_than_average = tuple()
for number in numbers:
if number > average:
greater_than_average += (number,)
print("Элементы больше среднего:", greater_than_average)
Пример 7. Возрастающая прогрессия (задача из домашнего задания)
В новый кортеж попадают только элементы, каждый из которых больше всех предыдущих — то есть каждый новый «рекорд» по ходу перебора.
numbers = (3, 7, 2, 8, 5, 10, 1)
increasing = tuple()
current_max = None
for number in numbers:
if current_max is None or number > current_max:
increasing += (number,)
current_max = number
print("Кортеж по возрастанию:", increasing) # (3, 7, 8, 10)
Как проверить себя: 2, 5 и 1 не попали в результат — каждое из них меньше, чем уже встреченный максимум (7, 8 и 10 соответственно). current_max = None в начале нужен, чтобы первый элемент попал в результат всегда, независимо от его значения.
Пример 8. Сравнение соседних элементов
numbers = (10, 20, 15, 30, 25, 35)
for index, value in enumerate(numbers[:-1]):
next_value = numbers[index + 1]
if value > next_value:
print(f"{value} больше, чем {next_value}")
Срез numbers[:-1] защищает от выхода за границы: последний элемент не сравнивается с несуществующим следующим.
Пример 9. Индексы повторяющихся элементов
numbers = (1, 2, 3, 4, 2, 5, 3, 6, 4, 2, 9)
processed = tuple()
for number in numbers:
if numbers.count(number) > 1 and number not in processed:
indexes = tuple()
for index, current in enumerate(numbers):
if current == number:
indexes += (index,)
processed += (number,)
print(f"Индексы элемента {number}:", *indexes)
Что происходит: numbers.count(number) > 1 — это единственное место в примерах, где нужен метод count(); processed не даёт напечатать один и тот же элемент дважды, если он повторяется больше двух раз.
Пример 10. Распаковка остатка через *
numbers = (3, 7, 2, 8, 5, 10, 1)
first, *middle, last = numbers
print("Первый:", first)
print("Середина:", middle) # [7, 2, 8, 5, 10] — список, не кортеж
print("Последний:", last)
Пример 11. Ловушка: изменяемый объект внутри неизменяемого кортежа
Сам кортеж неизменяем, но ничто не мешает ему хранить изменяемый объект — например, список. Нельзя заменить список внутри кортежа на другой, но можно изменить содержимое этого списка.
data = ([1, 2], "items")
data[0].append(3) # список внутри кортежа изменился
print(data) # ([1, 2, 3], 'items')
try:
data[0] = [9, 9] # а вот заменить сам элемент кортежа нельзя
except TypeError as error:
print("TypeError:", error)