Сохранить память для списка в Python?

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

Edit: Кроме того, имеет ли смысл делать что-то подобное на языке Python? Я довольно опытный программист, но новичок в Python и все еще чувствую, как он работает. Является ли Python внутренне выделять объекты all в отдельных пространствах кучи, преуменьшая цель попытки свести к минимуму выделения или примитивы, такие как int, float и т.д., Хранящиеся непосредственно в списках?

+42
источник поделиться
7 ответов

Здесь четыре варианта:

  • создание инкрементного списка
  • "предварительно выделенный" список
  • array.array()
  • numpy.zeros()

 

python -mtimeit -s"N=10**6" "a = []; app = a.append;"\
    "for i in xrange(N):  app(i);"
10 loops, best of 3: 390 msec per loop

python -mtimeit -s"N=10**6" "a = [None]*N; app = a.append;"\
    "for i in xrange(N):  a[i] = i"
10 loops, best of 3: 245 msec per loop

python -mtimeit -s"from array import array; N=10**6" "a = array('i', [0]*N)"\
    "for i in xrange(N):" "  a[i] = i"
10 loops, best of 3: 541 msec per loop

python -mtimeit -s"from numpy import zeros; N=10**6" "a = zeros(N,dtype='i')"\
    "for i in xrange(N):" "  a[i] = i"
10 loops, best of 3: 353 msec per loop

Это показывает, что [None]*N является самым быстрым, а array.array является самым медленным в этом случае.

+34
источник

вы можете создать список известной длины следующим образом:

>>> [None] * known_number
+13
источник

Взгляните на это:

In [7]: %timeit array.array('f', [0.0]*4000*1000)
1 loops, best of 3: 306 ms per loop

In [8]: %timeit array.array('f', [0.0])*4000*1000
100 loops, best of 3: 5.96 ms per loop

In [11]: %timeit np.zeros(4000*1000, dtype='f')
100 loops, best of 3: 6.04 ms per loop

In [9]: %timeit [0.0]*4000*1000
10 loops, best of 3: 32.4 ms per loop

Поэтому никогда не используйте array.array('f', [0.0]*N), используйте array.array('f', [0.0])*N или numpy.zeros.

+8
источник

В большинстве повседневных кодов вам не нужна такая оптимизация.

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

Здесь создается список из 4 миллионов чисел чисел с плавающей запятой:

import array
lst = array.array('f', [0.0]*4000*1000)
+5
источник

Если вы хотите эффективно управлять числами в Python, посмотрите на NumPy ( http://numpy.scipy.org/). Это позволяет вам делать что-то очень быстро, продолжая использовать Python.

Чтобы сделать то, что вы задали в NumPy, вы бы сделали что-то вроде

import numpy as np
myarray = np.zeros(4000)

который даст вам массив чисел с плавающей запятой, инициализированных до нуля. Затем вы можете сделать очень классные вещи, например, умножить целые массивы на один фактор или на другие массивы и другие вещи (вроде как в Matlab, если вы когда-либо использовали это), что очень быстро (большая часть фактической работы происходит в высоко оптимизированная часть C библиотеки NumPy).

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

+4
источник

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

+2
источник

для Python3:

import timeit
from numpy import zeros
from array import array

def func1():
    N=10**6
    a = []
    app = a.append
    for i in range(N):
        app(i)

def func2():
    N=10**6
    a = [None]*N
    app = a.append
    for i in range(N):
        a[i] = i

def func3():
    N=10**6
    a = array('i', [0]*N)
    for i in range(N):
        a[i] = i

def func4():
    N=10**6
    a = zeros(N,dtype='i')
    for i in range(N):
        a[i] = i

start_time = timeit.default_timer()
func1()
print(timeit.default_timer() - start_time)

start_time = timeit.default_timer()
func2()
print(timeit.default_timer() - start_time)

start_time = timeit.default_timer()
func3()
print(timeit.default_timer() - start_time)

start_time = timeit.default_timer()
func4()
print(timeit.default_timer() - start_time)

результат:

0.1655518
0.10920069999999998
0.1935983
0.15213890000000002
  1. добавление()
  2. [Отсутствует] * N
  3. используя массив модулей
  4. используя модуль NumPy
0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос