Como criar uma lista com um tamanho específico em Python
- Pré-alocação de armazenamento para listas
- Pré-alocação de armazenamento para outras estruturas de dados sequenciais
A pré-alocação de armazenamento para listas ou arrays é um padrão típico entre os programadores
quando eles sabem o número de elementos antes do tempo.
Ao contrário do C++ e Java, em Python, você tem que inicializar todo o seu armazenamento pré-alocado com alguns valores.
Normalmente, desenvolvedores utilizam valores falsos para esse fim, como None
, ''
, False
, e 0
.
Python oferece várias maneiras de criar uma lista de tamanho fixo, cada uma com
características de desempenho diferentes.
Para comparar desempenhos de diferentes abordagens, usaremos o padrão Python
módulo timeit
.
Ele fornece uma maneira útil de medir tempos de execução de pequenos pedaços de código Python.
Pré-alocação de armazenamento para listas
A primeira e mais rápida forma de utilizar o operador *
, que repete uma lista de
número de vezes.
>>> [None] * 10
[None, None, None, None, None, None, None, None, None, None]
Um milhão de iterações (valor padrão das iterações no timeit
) leva aproximadamente
117 ms.
>>> timeit("[None] * 10")
0.11655918900214601
Outra abordagem é utilizar a função embutida range
com uma lista de compreensão.
>>> [None for _ in range(10)]
[None, None, None, None, None, None, None, None, None, None]
É quase seis vezes mais lento e leva 612 ms de segundo por milhão de iterações.
>>> timeit("[None for _ in range(10)]")
0.6115895550028654
A terceira abordagem é utilizar um simples loop for
junto com o list.append()
.
>>> a = []
>>> for _ in range(10):
... a.append(None)
...
>>> a
[None, None, None, None, None, None, None, None, None, None]
A utilização de loops é o método mais lento e leva 842 ms para completar um milhão de iterações.
>>> timeit("for _ in range(10): a.append(None)", setup="a=[]")
0.8420009529945673
Pré-alocação de armazenamento para outras estruturas de dados sequenciais
Como você está pré-alocando o armazenamento para uma estrutura de dados sequencial, pode fazer muito sentido utilizar a estrutura de dados embutida Array em vez de uma lista.
>>> from array import array
>>> array('i',(0,)*10)
array('i', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
Como vemos abaixo, esta abordagem é a segunda mais rápida depois de [None] * 10
.
>>> timeit("array('i',(0,)*10)", setup="from array import array")
0.4557597979946877
Vamos comparar as abordagens Python puras acima com o pacote NumPy
Python para computação científica.
>>> from numpy import empty
>>> empty(10)
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
O modo NumPy leva 589 ms por milhão de iterações.
>>> timeit("empty(10)", setup="from numpy import empty")
0.5890094790011062
Entretanto, o modo NumPy será muito mais rápido para listas mais massivas.
>>> timeit("[None]*10000")
16.059584009999526
>>> timeit("empty(10000)", setup="from numpy import empty")
1.1065983309963485
A conclusão é que é melhor se ater a [None] * 10
para listas pequenas, mas trocar
para NumPy’s empty()
ao lidar com dados seqüenciais mais maciços.
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook