Как создать список с определенным размером на Python
- Предварительное размещение хранилища для списков
- Предварительное выделение хранилища для других последовательных структур данных
Предварительное выделение хранилища для списков или массивов - типичный шаблон среди программистов. когда они заранее знают количество элементов.
В отличие от C++ и Java, в Python, вы должны инициализировать все ваше предварительно распределенное хранилище некоторыми значениями.
Обычно разработчики используют для этого ложные значения, такие как None
, ""
, False
и 0
.
Python предлагает несколько способов создания списка фиксированного размера, каждый из которых включает в себя различные эксплуатационные характеристики.
Для сравнения характеристик различных подходов мы будем использовать стандарт Python
модуль timeit
.
Он предоставляет удобный способ измерения времени выполнения небольших фрагментов кода Python.
Предварительное размещение хранилища для списков
Первый и самый быстрый способ использования оператора *
, который повторяет список указанных
несколько раз.
>>> [None] * 10
[None, None, None, None, None, None, None, None, None, None]
Миллион итераций (значение итераций по умолчанию в timeit
) занимает приблизительно
117 мс.
>>> timeit("[None] * 10")
0.11655918900214601
Другой подход - использование встроенной функции range
с пониманием списка.
>>> [None for _ in range(10)]
[None, None, None, None, None, None, None, None, None, None]
Она почти в шесть раз медленнее и занимает 612 мс в секунду на миллион итераций.
>>> timeit("[None for _ in range(10)]")
0.6115895550028654
Третий подход - использование простого цикла for
вместе с list.append()
.
>>> a = []
>>> for _ in range(10):
... a.append(None)
...
>>> a
[None, None, None, None, None, None, None, None, None, None]
Использование циклов является самым медленным методом и занимает 842 мс на миллион итераций.
>>> timeit("for _ in range(10): a.append(None)", setup="a=[]")
0.8420009529945673
Предварительное выделение хранилища для других последовательных структур данных
Так как вы предварительно распределяете хранилище для последовательной структуры данных, то, возможно, имеет смысл использовать array
встроенную структуру данных вместо списка.
>>> from array import array
>>> array('i',(0,)*10)
array('i', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
Как видно ниже, такой подход является вторым по скорости после [None] * 10
.
>>> timeit("array('i',(0,)*10)", setup="from array import array")
0.4557597979946877
Сравним вышеприведенные подходы чистого Python с пакетом NumPy
Python для научных вычислений.
>>> from numpy import empty
>>> empty(10)
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
Путь NumPy занимает 589 мс на миллион итераций.
>>> timeit("empty(10)", setup="from numpy import empty")
0.5890094790011062
Однако, для более массивных списков путь NumPy будет намного быстрее.
>>> timeit("[None]*10000")
16.059584009999526
>>> timeit("empty(10000)", setup="from numpy import empty")
1.1065983309963485
Вывод в том, что для маленьких списков лучше придерживаться [None] * 10
, но переключайтесь
в NumPy’s empty()
при работе с более массивными последовательными данными.