← Назад к вопросам

Как реализован кортеж в Python?

1.3 Junior🔥 241 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как реализован кортеж в Python

Кортеж (tuple) — это один из фундаментальных типов данных в Python, и его реализация имеет интересные особенности на уровне CPython.

Структура кортежа на C уровне

В CPython кортеж реализован как C структура PyTupleObject:

typedef struct {
    PyObject_HEAD
    Py_ssize_t ob_size;  // Количество элементов
    PyObject *ob_item[1];  // Указатели на элементы (массив переменной длины)
} PyTupleObject;

Ключевые особенности:

  • ob_item — это массив указателей на объекты Python
  • Размер кортежа (ob_size) фиксирован при создании
  • Данные лежат в памяти контигуально

Операции основных

# Создание
t = (1, 2, 3)  # Литеральный синтаксис
t = tuple([1, 2, 3])  # Конвертирование

# Чтение по индексу - O(1)
value = t[0]  # Прямой доступ к ob_item[0]

# Слайсинг - O(k) где k размер слайса
slice = t[1:3]  # Создаёт новый кортеж

# Итерация - O(n)
for item in t:
    print(item)

Неизменяемость (Immutability)

Кортеж является неизменяемым типом:

t = (1, 2, 3)
t[0] = 10  # TypeError: tuple object does not support item assignment
del t[0]   # TypeError: tuple object does not support item deletion
t.append(4)  # AttributeError: нет метода append

Реализация неизменяемости:

  • В CPython нет операций изменения кортежа
  • Попытка изменения вызывает исключение на уровне интерпретатора
  • Это позволяет безопасно использовать кортежи как ключи словарей

Хеширование

Кортежи хешируемы, если все их элементы хешируемы:

# Можно использовать как ключи словаря
dict_with_tuple_keys = {
    (1, 2): "value1",
    (3, 4): "value2"
}

# Но не если содержат списки
my_tuple = (1, [2, 3])  # Мутабельный элемент
hash(my_tuple)  # TypeError: unhashable type: 'list'

Реализация хеша:

  • Хеш кортежа вычисляется из хешей его элементов
  • Кэшируется внутри объекта кортежа для быстрого доступа

Оптимизация: Tuple pooling

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

# Пустой кортеж - всегда один и тот же объект
t1 = ()
t2 = ()
print(t1 is t2)  # True - один объект в памяти!

# Однозначные кортежи с целыми числами
t3 = (1,)
t4 = (1,)
print(t3 is t4)  # True в некоторых контекстах

# Больше нет гарантии
t5 = (1, 2)
t6 = (1, 2)
print(t5 is t6)  # Может быть True или False

Реализация методов

t = (1, 2, 3, 2, 1)

# count - O(n) поиск по значению
count_2 = t.count(2)  # 2

# index - O(n) первое вхождение
index_2 = t.index(2)  # 1

# len - O(1) просто читаем ob_size
len_t = len(t)  # 3

Упаковка и распаковка

# Упаковка - создаёт новый кортеж
a, b, c = 1, 2, 3  # Создаёт (1, 2, 3) затем распаковывает

# Распаковка - итерирует элементы
t = (10, 20, 30)
x, y, z = t  # Обращается к t[0], t[1], t[2]

# Extended unpacking
first, *middle, last = (1, 2, 3, 4, 5)
# first=1, middle=[2,3,4], last=5

Сравнение с другими типами

import sys

list_obj = [1, 2, 3]
tuple_obj = (1, 2, 3)

print(sys.getsizeof(list_obj))   # ~56 байт (зависит от системы)
print(sys.getsizeof(tuple_obj))  # ~40 байт (компактнее)

Преимущества кортежа:

  • Меньше памяти - нет выделения места для роста
  • Быстрее создание - размер известен
  • Хеширование - может быть ключом словаря
  • Потокобезопасность - не меняется

Производительность операций

import timeit

t = tuple(range(10000))
l = list(range(10000))

# Чтение по индексу - одинаково
print(timeit.timeit(lambda: t[5000], number=1000000))  # ~0.04s
print(timeit.timeit(lambda: l[5000], number=1000000))  # ~0.04s

# Создание
print(timeit.timeit(lambda: (1, 2, 3), number=1000000))     # Быстро
print(timeit.timeit(lambda: [1, 2, 3], number=1000000))     # Немного медленнее

# Итерация
print(timeit.timeit(lambda: [x for x in t], number=10000))  # ~0.3s
print(timeit.timeit(lambda: [x for x in l], number=10000))  # ~0.3s

Named tuples - расширение

from collections import namedtuple

# Более удобный синтаксис
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x)  # 10
print(p[0])  # 10

# Это всё ещё кортеж
print(isinstance(p, tuple))  # True
print(hash(p))  # Хешируется

Резюме

  • Структура: Массив указателей на Python объекты с фиксированным размером
  • Неизменяемость: Встроена на уровне интерпретатора
  • Хеширование: Вычисляется и кэшируется
  • Оптимизация: Пулинг пустых и однозначных кортежей
  • Производительность: Компактнее и быстрее создаётся чем список
  • Use case: Ключи словарей, множеств, возвращаемые значения, потокобезопасность