Сравнение списков и кортежей в Python. Какой из них более эффективен и когда его использовать?

Несмотря на то, что Python является одним из самых популярных языков программирования из-за своей простоты, он также известен своей относительной медлительностью и неэффективностью. Его гибкие правила позволяют вам легко писать впечатляющее программное обеспечение, но та же самая гибкость может привести к созданию действительно неэффективного кода.

В частности, синтаксис Python не навязывает какой-либо стиль кодирования и не накладывает никаких ограничений на подход, который вы можете использовать для решения конкретной проблемы. Более того, разработчики Python обычно не изучают оптимизацию нижнего уровня, потому что все абстрагируется.

Самый распространенный способ хранения группы данных в Python — это список.

И это нормально при прототипировании или если эти списки будут доступны только несколько раз во время выполнения программы. С другой стороны, ваш код может стать излишне медленным из-за использования неправильного типа коллекции элементов внутри критических функций.

Размер объектов Python

Как многие из вас знают, в Python все является объектом. Это означает, что вы не можете работать с необработанными типами данных, как в языках более низкого уровня, таких как C. Из-за этого объекты Python занимают больше памяти, чем значение, которое они содержат.

Вывод консоли:

0:            24 bytes
1:            28 bytes
1.0:          24 bytes
555555555555: 32 bytes

Как видите, их размер намного больше, чем размер реального значения, которое они хранят. Это связано с тем, что объекты Python также включают ссылки на методы и другие атрибуты, обеспечивающие функциональность типа.

Возвращаясь к спискам, они также предоставляют вам методы и операторы для взаимодействия с ними. Эти атрибуты, очевидно, занимают некоторое пространство, но к большинству из них в большинстве случаев никогда не обращаются. Например, если вам не нужно изменять список в вашей программе, нет необходимости включать методы, которые это делают. В этом случае вы также можете использовать неизменяемый тип коллекции.

Чем отличаются кортежи?

Кортежи Python — это, по сути, списки, но они неизменяемы. Это означает, что вы не можете изменять элементы кортежа, добавлять или удалять их. Если вы попытаетесь присвоить элементу другое значение, вы получите сообщение об ошибке:

>>> t = (1,2,3)
>>> t[0] = 4
TypeError: 'tuple' object does not support item assignment

Объекты Tuple не реализуют методы для их изменения, поэтому для их хранения фактически требуется меньше памяти. Вот краткое сравнение списков и кортежей с точки зрения размера:

Вывод консоли:

Empty list:   72 bytes
Filled list: 112 bytes
Empty tuple:  56 bytes
Filled tuple: 96 bytes

Как видите, кортежи занимают значительно меньше памяти, чем списки. А именно, пустой список требует на 16 байт больше, чем кортеж. Кроме того, Python может выделить больше памяти, чем это необходимо, чтобы избежать изменения размера, если вы добавите в коллекцию какой-либо новый элемент.

Преимущества производительности скорости

Кортежи не только более эффективны с точки зрения требований к памяти, но и обеспечивают преимущество в скорости по сравнению со списками. Фактически, их время доступа значительно быстрее, чем у их аналога.

Вывод консоли:

Lists average: 0.0020666594509384595 seconds
Tuples average: 0.0014251830289140344 seconds
Tuples are on average 1.4501 (~69%) times faster than lists

Как видите, прирост производительности весьма значителен. Теперь представьте, сколько времени вы бы сэкономили, если бы вам приходилось обращаться к элементам вашей коллекции несколько раз в секунду.

Примеры использования кортежей

Теперь ясно, что кортежи более эффективны, чем списки. Их следует использовать вместо списков всякий раз, когда вы заранее знаете, что коллекция не изменится во время выполнения вашей программы. Вот несколько реальных случаев использования кортежей:

  • Таблицы для группировки констант. Поскольку константы никогда не меняются, имеет смысл хранить их внутри неизменяемой структуры данных.
  • Неизменяемые составные объекты. Если вы не планируете изменять атрибут списка объекта, вы можете заменить его кортежем.
  • Временные коллекции только для чтения. Если коллекция повторяется только один раз и не изменяется, лучше использовать кортеж.

Заключение

Подводя итог, Python — действительно гибкий язык и предлагает широкий спектр инструментов. Проблема в том, что он не применяет передовой опыт, что приводит разработчиков к плохим привычкам с точки зрения эффективности.

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

В жизни нет универсального подхода. Все сводится к использованию правильного инструмента для правильной работы.

Надеюсь, вам понравилась эта статья. Если вы заинтересованы в дальнейшей оптимизации своих программ, я настоятельно рекомендую вам ознакомиться с моей статьей о расширениях C для Python:



Спасибо за прочтение!