Как Python может хранить разные типы объектов в одном списке и эффективно с ними работать?

«Как Python может хранить разные типы объектов в одном списке и эффективно с ними работать?» — вопрос из категории Python, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Python списки хранят не сами объекты, а ссылки (указатели) на объекты в памяти. Это архитектурное решение обеспечивает две ключевые возможности:

1. Гетерогенность содержимого:

mixed_list = [
    42,                     # int
    "строка",              # str
    3.14,                  # float
    lambda x: x**2,        # function
    {'key': 'value'},      # dict
    [1, 2, 3],             # list
    None                   # NoneType
]

for i, item in enumerate(mixed_list):
    print(f"Элемент {i}: {type(item).__name__} = {item}")

2. Эффективность операций:

  • Все элементы списка имеют одинаковый размер (размер указателя, обычно 8 байт)
  • Доступ по индексу происходит за O(1), так как это просто вычисление смещения в массиве указателей
  • Операции вставки/удаления в конце списка амортизированно O(1)

Как это работает в CPython:

/* Упрощенная структура списка в CPython */
typedef struct {
    PyObject **ob_item;     /* массив указателей на PyObject */
    Py_ssize_t allocated;   /* выделенная память */
} PyListObject;

Практическое следствие: При итерации по списку Python разыменовывает каждый указатель, получая доступ к реальному объекту и его типу. Динамическая типизация проверяется во время выполнения через механизм PyObject_TypeCheck.

Важно: Эта гибкость имеет стоимость — дополнительные накладные расходы на разыменование и проверку типов по сравнению со статически типизированными массивами в языках типа C++ или Java.