Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 19 из 20 Начальный 15 мин 100 XP

Задачи на кортежи Python: практика с решениями

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

Редакция Питоники

Уроки про кортежи дали три права: неизменяемость из урока 11, сравнение со списком из урока 12, распаковка из урока 13. Пять задач ниже показывают эти права за работой: координаты в функциях, статистика одним вызовом, записи, которые не испортить, и ходы как ключи словаря. К каждой — код, честный вывод и разбор, почему кортеж здесь лучше списка.

Задача 1: координаты проходят через функции

Точка на плоскости — пара чисел, и кортеж для неё естественен: фиксированный состав, два значения, защита от случайной правки. Напишем сложение точек — функция принимает два кортежа и возвращает новый:

решение: кортеж на входе, кортеж на выходе
def add_points(a, b):
    return (a[0] + b[0], a[1] + b[1])

p1 = (2, 3)
p2 = (5, 7)
p3 = add_points(p1, p2)

print(p1, '+', p2, '=', p3)
print(p3[0] - p1[0], p3[1] - p1[1])
Вывод
(2, 3) + (5, 7) = (7, 10)
5 7

Кортеж приехал в функцию, из функции вышел кортеж — идиома возврата из урока 14. Печать кортежа целиком безопасна: (7, 10) стабилен, в отличие от множеств. Вторая печать — проверка: разность между суммой и первым слагаемым вернула второе слагаемое, сложение честное.

Задача 2: максимум и минимум сразу

Таблица результатов: имя и очки. Нужно найти рекордсмена и вывести таблицу по убыванию очков. Функция max с параметром key читает у каждой записи поле очков, а sorted с тем же key раскладывает записи:

решение: key по второму элементу
results = [
    ('Анна', 12),
    ('Борис', 9),
    ('Вера', 15),
    ('Глеб', 9),
]

best = max(results, key=lambda r: r[1])
print('рекордсмен:', best)
print('имя:', best[0], '- очков:', best[1])
print()
for name, score in sorted(results, key=lambda r: r[1], reverse=True):
    print(name, '-', score)
Вывод
рекордсмен: ('Вера', 15)
имя: Вера - очков: 15

Вера - 15
Анна - 12
Борис - 9
Глеб - 9

Обратите внимание на Бориса и Глеба: очки равные, и порядок между ними остался исходный. Сортировка Python стабильна — равные элементы сохраняют прежний порядок, и таблица предсказуема. Распаковка в заголовке цикла из урока 13 дала колонки name и score без индексов.

Задача 3: запись, которую не испортить

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

решение: попытка правки падает
record = ('Анна', 25, 'Москва')

try:
    record[1] = 26
except TypeError as e:
    print('TypeError:', e)

print('возраст по записи:', record[1])
Вывод
TypeError: 'tuple' object does not support item assignment
возраст по записи: 25

Кортеж не запрещает работать с данными — он запрещает портить их случайно: правка записи падает громко и сразу, а не портит отчёт. Возраст 25 пережил попытку. Если день рождения наступил — строится новая запись из старой: updated = (record[0], 26, record[2]), и старая остаётся нетронутой.

Задача 4: ходы как ключи словаря

В логе игры записаны ходы — пары координат сдвига. Задача: посчитать, какой ход делали чаще. Пара — ключ словаря, и тут кортеж незаменим: список ключом быть не может, потому что у него нет хеша из урока 17:

решение: счётчик с ключами-кортежами
moves = [(0, 1), (1, 0), (0, 1), (0, 1), (1, 0), (1, 1)]

counts = {}
for m in moves:
    counts[m] = counts.get(m, 0) + 1

print('разных ходов:', len(counts))
for move, n in sorted(counts.items()):
    print(move, '-', n)
Вывод
разных ходов: 3
(0, 1) - 3
(1, 0) - 2
(1, 1) - 1

Шесть ходов свелись к трём разным: ключи-кортежи сами отфильтровали повторы, get с нулём по умолчанию завёл счётчик с первого вхождения. Печать items() через sorted дала порядок по ключам: (0, 1) меньше (1, 0), потому что сравнение кортежей идёт поэлементно. Тот же приём — подсчёт частот — встретился в задачах на множества, только там ключами были имена, здесь — пары.

Задача 5: кортеж из одного элемента

Задача на чтение чужого кода, и в ней чаще всего ошибаются: чем отличается (5) от (5,)? Ответ — всем: скобки создают не кортеж, кортеж делает запятая:

решение: запятая решает
not_tuple = (5)
is_tuple = (5,)

print(type(not_tuple).__name__, type(is_tuple).__name__)
print(len(is_tuple))
print(type((1, 2)).__name__)
Вывод
int tuple
1
tuple

(5) — число в скобках, как в школьной арифметике: приоритет вычислений. (5,) — кортеж из одного элемента, и len подтверждает. Отсюда привычка: единственный элемент кортежа в данных или параметрах пишите с хвостовой запятой — она не мешает и при расширении записи до двух полей.

рост через новую сборку
point = (1, 2)
extended = point + (3,)

print(point)
print(extended)
Вывод
(1, 2)
(1, 2, 3)

Исходная точка не изменилась — кортеж не умеет меняться, и сложение вернуло новый объект. Правило то же, что у строк: любые «изменения» — это новые значения, старые остаются при своих данных.

умножение кортежа копит один список
rows = ([],) * 3
rows[0].append('X')

print(rows)
Вывод
(['X'], ['X'], ['X'])
ЗадачаИнструментЧто даёт кортеж
Точки и векторыФункция с кортежамиФиксированный состав, возврат пары
Максимум по полюmax(key=lambda r: r[1])Запись целиком, не только число
Защита записиНеизменяемостьПравка падает вместо порчи данных
Счётчик ходовКортеж-ключ словаряПары как уникальные ключи
Один элемент(5,) с запятойЗапятая делает кортеж, скобки нет

Что дальше

Пять задач закрыли повседневную жизнь кортежей: передача через функции, максимум по полю, защита записей, ключи словаря, единичный элемент. Остался последний шаг раздела — проект по анализу посетителей: журнал визитов, где множества отвечают за уникальность и пересечения, а кортежи — за возвраты из функций и ключи. Читайте namedtuple, если записи захотят имён полей.

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

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

t = (7,)
print(len(t), type(t).__name__)
print(t * 2)
pairs = [(1, 'b'), (2, 'a'), (3, 'b')]
print(sorted(pairs, key=lambda p: p[1])[0])
x, y = (10, 20)
point = (y, x)
print(point)
Проверь себя
0 / 7

1. Функция add_points принимает два кортежа и возвращает сумму. Что она вернёт?

2. Как найти запись с максимальными очками в списке кортежей (имя, очки)?

3. Борис и Глеб набрали поровну очков. В каком порядке они окажутся после sorted по очкам?

4. record[1] = 26 у кортежа упадёт. Что говорит эта ошибка?

5. Почему ходы (0, 1) годятся в ключи словаря, а списки [0, 1] — нет?

6. Чем (5) отличается от (5,)?

7. Как «добавить» элемент к кортежу point = (1, 2)?

Карточки терминов
Запомнено: 0 / 8
Практика

Даны два кортежа координат a = (2, 3) и b = (4, 6). Напишите функцию midpoint, возвращающую кортеж со средними координатами (по каждой оси — среднее двух чисел), и напечатайте её результат.

practice.py
Вопросы и ответы по уроку

Как передать в функцию и вернуть из неё пару значений-координат?

Кортежем: def add_points(a, b): return (a[0] + b[0], a[1] + b[1]). Кортеж на входе защищает координаты от правок, кортеж на выходе — идиома возврата нескольких значений из урока 14.

Урок 14: функция возвращает несколько значений

Как найти максимум в списке кортежей по одному полю?

max(items, key=lambda item: item[1]) — параметр key говорит, по какому элементу сравнивать, и возвращает запись целиком. Для сортировки по полю — sorted(items, key=lambda item: item[1]); сортировка стабильна, равные сохраняют исходный порядок.

Зачем хранить записи кортежами, если список умеет всё то же?

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

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

Как посчитать, сколько раз встречалась каждая пара значений?

Словарём с ключами-кортежами: counts[pair] = counts.get(pair, 0) + 1. Кортеж хешируем, поэтому годится в ключ; список — нет. Печать через sorted(counts.items()) даёт порядок по ключам: кортежи сравниваются поэлементно.

Почему (5) не кортеж?

Кортеж создаёт запятая, а не скобки: (5) — это число 5 в скобках приоритета, type покажет int. Кортеж из одного элемента пишется (5,) — запятая обязательна и не мешает при расширении записи.

Понравился урок? Сошлитесь на него

«Кортеж не запрещает работать с данными — он запрещает портить их случайно: правка записи падает громко и сразу, а не портит отчёт.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.