Перейти к содержимому
Теория · Кортежи и распаковка · урок 1 из 8

Кортежи

Чему вы научитесь

Чему вы научитесь:

  • собирать несколько значений в кортеж и читать их по индексу;
  • объяснять, чем кортеж отличается от списка и когда какой выбрать;
  • раскладывать кортеж по переменным распаковкой, в том числе со звёздочкой;
  • перебирать номера и пары значений с помощью enumerate и zip.
Машина divide выдаёт одну запаянную упаковку (3, 2) с двумя плитками внутри

Представьте настольный автомат с надписью divide. Вы кладёте в него два числа, 17 и 5, и он делит одно на другое с остатком. Ответов получается два: частное 3 и остаток 2. А лоток для выдачи у автомата один.

Автомат выходит из положения так: кладёт обе плитки с числами в одну запаянную упаковку и выдаёт её. На упаковке написано (3, 2), а внутри видны две плитки. Вы получаете один предмет, и в нём оба ответа по порядку.

Функция в Python устроена так же: return отдаёт ровно одно значение. Если после return перечислить значения через запятую, Python соберёт их в один объект — кортеж:

Python
def divide(a, b):
    return a // b, a % b


result = divide(17, 5)
print(result)  # (3, 2)
print(result[0], result[1])  # 3 2
print(len(result), type(result))  # 2 <class 'tuple'>

Давайте разберём пример по строкам:

  1. return a // b, a % b вычисляет частное и остаток и собирает их в кортеж (3, 2).
  2. result = divide(17, 5) даёт имя result всей упаковке целиком.
  3. print(result) показывает кортеж так, как его записывают: элементы через запятую в круглых скобках.
  4. result[0] — частное, result[1] — остаток.
  5. len(result) равно 2, а type сообщает, что это tuple.

Кортеж — это последовательность

Кортеж — последовательность, как строка и список. Поэтому с ним работает всё, что вы уже знаете по строкам и спискам:

  • индексы, в том числе отрицательные: result[-1] — последний элемент;
  • срезы, и срез кортежа — тоже кортеж;
  • функция len и оператор in;
  • цикл for, который перебирает элементы по порядку.

Кортеж не меняется

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

Python
point = (3, 4)
point[0] = 5  # ✗
TEXT
TypeError: 'tuple' object does not support item assignment

Python останавливает программу на этой строке. Методов append, pop и sort у кортежа тоже нет. Чтобы получить другую точку, создают новый кортеж: point = (5, point[1]). Имя point теперь указывает на новую упаковку, а старая осталась прежней.

Здесь аналогия перестаёт работать. В кортеже лежат не копии, а сами объекты, и список внутри кортежа по-прежнему можно менять.

Например, в кортеже t = ([1, 2], 3) строка t[0].append(5) сработает, и t станет ([1, 2, 5], 3). Неизменным остаётся только состав кортежа: какие объекты в нём лежат и в каком порядке.

Кортеж или список

Этот вопрос часто задают на собеседовании: «Чем кортеж отличается от списка?» Главное отличие вы уже знаете: список меняется, а кортеж — нет. Из него следует, где какой уместен.

Список

Список выбирают для набора однотипных значений, число которых меняется: покупки, оценки, имена. В такой набор добавляют элементы, удаляют их и сортируют на месте.

Кортеж

Кортеж подходит для записи постоянной формы, где у каждой позиции свой смысл:

  • точка (x, y);
  • дата (year, month, day);
  • несколько результатов одной функции, как у divide.

Такую запись не испортит случайный append или присваивание по индексу. Это верно даже внутри функции, которой кортеж передали аргументом.

Функции tuple() и list() превращают список в кортеж и обратно: tuple([1, 2]) даёт (1, 2), а list((1, 2)) — [1, 2].

Кортеж создаёт запятая

Скобки вокруг кортежа пишут для наглядности, а создаёт его запятая. Отсюда три правила записи:

  • pair = 3, 4 — кортеж из двух элементов, даже без скобок;
  • (7,) — кортеж из одного элемента: запятая стоит после элемента;
  • () — пустой кортеж, пара скобок без запятой.
Python
pair = 3, 4
single = (7,)
empty = ()
print(pair, single, empty)  # (3, 4) (7,) ()
print(len(single), len(empty))  # 1 0

print тоже показывает кортеж из одного элемента с запятой: (7,). Это кортеж, а не число, поэтому сравнение (7,) == 7 даёт False.

Частая ошибка

Кортеж из одного элемента записали без запятой:

Python
colors = ("red")  # ✗
for c in colors:
    print(c, end=" ")  # r e d

Ошибки нет, но цикл печатает буквы. Скобки вокруг одного значения только группируют его, как в (2 + 3) * 4. Поэтому ("red") — это строка "red", и цикл идёт по её символам.

Точно так же (1) — это int 1, и сравнение (1) == 1 даёт True. С запятой ("red",) получается кортеж из одной строки, и цикл печатает red.

Главное

  • Значения через запятую собираются в один объект — кортеж; так функция возвращает несколько результатов.
  • Кортеж читают как список — по индексу, срезом, в цикле, — но изменить его нельзя.
  • Список хранит меняющийся набор однотипных значений, кортеж — запись постоянной формы.
  • Кортеж создаёт запятая: (7,) — кортеж, а (7) — число 7.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом