Ответ
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.