Кортежи и распаковка
Кортеж
Кортеж (tuple) — неизменяемая упорядоченная последовательность.
point = (3, 4)
person = ("Анна", 28, "Москва")
single = (42,) # кортеж из одного элемента — нужна запятая!
not_tuple = (42) # это просто число в скобках
empty = ()
no_parens = 1, 2, 3 # кортеж создаёт запятая, скобки не обязательны
print(type(single), type(not_tuple), no_parens)
print(point[0], person[-1], person[1:], len(person))
print(person.count(28), person.index("Москва"))
point = (3, 4)
point[0] = 10 # TypeError: 'tuple' object does not support item assignment
Зачем кортежи, если есть списки
list |
tuple |
|
|---|---|---|
| Изменяемость | да | нет |
Можно ключом словаря / в set |
нет | да (если элементы хешируемы) |
| Типичный смысл | однородная коллекция переменной длины | фиксированная запись: каждая позиция имеет свой смысл |
| Память и скорость создания | больше | немного меньше и быстрее |
# координаты как ключи словаря
distances = {(0, 0): 0, (3, 4): 5}
print(distances[(3, 4)])
# кортеж занимает меньше памяти
import sys
print(sys.getsizeof([1, 2, 3]), sys.getsizeof((1, 2, 3)))
На собеседовании
«Чем list отличается от tuple?» — изменяемость; хешируемость (ключи словаря); семантика (однородные данные против записи); кортеж немного компактнее и создаётся быстрее, константные кортежи компилятор хранит прямо в байткоде.
Распаковка
x, y = (3, 4)
name, age, city = ["Анна", 28, "Москва"] # распаковывается любое итерируемое
first, *rest = [1, 2, 3, 4]
*init, last = "abcd"
head, *_, tail = range(10) # _ — «ненужная» переменная
print(first, rest, init, last, head, tail)
# вложенная распаковка
(x1, y1), (x2, y2) = [(0, 0), (3, 4)]
print(x2 - x1, y2 - y1)
# распаковка в цикле
for name, score in [("Аня", 90), ("Боря", 75)]:
print(name, score)
a, b = [1, 2, 3] # ValueError: too many values to unpack (expected 2)
Звёздочка при вызове и создании
def area(w, h):
return w * h
size = (3, 4)
print(area(*size)) # распаковать кортеж в аргументы
a = [1, 2]
b = (3, 4)
print([*a, *b, 5], (*a, *b)) # склеить в новый список / кортеж
Неизменяемость «поверхностная»
t = (1, [2, 3])
t[1].append(4) # список внутри изменяемый
print(t)
try:
hash(t)
except TypeError as e:
print("Не хешируется:", e)
Запустите 👣 Пошагово: кортеж хранит ссылку на список #2, и меняется именно список.
Именованные кортежи
Когда позиций много, person[2] становится непонятным. namedtuple даёт доступ по именам:
from collections import namedtuple
from typing import NamedTuple
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
print(p.x, p.y, p, p[0])
class Employee(NamedTuple): # современный синтаксис с аннотациями
name: str
salary: int = 100_000
e = Employee("Анна")
print(e, e._replace(salary=150_000), e._asdict())
Именованный кортеж остаётся кортежем: неизменяем, распаковывается, сравнивается. Для изменяемых записей используйте dataclass (урок в модуле ООП).
Итог
- Кортеж — неизменяемая последовательность; создаёт его запятая:
(42,). - Используйте для фиксированных записей, ключей словаря, возврата нескольких значений.
- Распаковка:
a, b = ...,first, *rest = ..., вложенная, в цикле;*при вызове функции. - Неизменяемость поверхностная: изменяемые объекты внутри меняются, и такой кортеж не хешируется.
namedtuple/typing.NamedTuple— кортеж с именованными полями.
Практика решено 0 из 5
Какой тип у x = (5) и у y = (5,)?
Напишите функцию stats(nums), которая возвращает кортеж (минимум, максимум, среднее).
Среднее округлите до 2 знаков.
Какие тесты проверяют код (3)
assert stats([1, 2, 3, 4]) == (1, 4, 2.5) assert isinstance(stats([5]), tuple) assert stats([2, 2, 3]) == (2, 3, 2.33)
def stats(nums):
return min(nums), max(nums), round(sum(nums) / len(nums), 2)
Используя распаковку со звёздочкой, напишите функцию head_tail(seq), которая возвращает
кортеж (первый элемент, список остальных). head_tail([1, 2, 3]) → (1, [2, 3]).
Какие тесты проверяют код (3)
assert head_tail([1, 2, 3]) == (1, [2, 3])
assert head_tail("ab") == ("a", ["b"])
assert head_tail([7]) == (7, [])
def head_tail(seq):
head, *tail = seq
return head, tail
Можно ли изменить кортеж t = (1, [2, 3]) так, чтобы получилось (1, [2, 3, 4])?
Где уместно использовать кортеж вместо списка?
Войдите, чтобы отмечать пройденные уроки.