Inicializando una lista a un número conocido de elementos en Python

En este momento estoy usando una lista, y esperaba algo como:

verts = list (1000) 

¿Debo usar array en su lugar?

Lo primero que me viene a la mente es:

 verts = [None]*1000 

¿Pero realmente necesitas preinicializarlo?

No estoy seguro de por qué todo el mundo le está dando un mal momento para querer hacer esto; hay varios escenarios en los que querría una lista inicializada de tamaño fijo. Y has deducido correctamente que los arreglos son sensibles en estos casos.

 import array verts=array.array('i',(0,)*1000) 

Para los que no son pythonistas, el término (0,)*1000 está creando una tupla que contiene 1000 ceros. La coma obliga a Python a reconocer (0) como una tupla, de lo contrario se evaluaría como 0.

He usado una tupla en lugar de una lista porque generalmente tienen menos gastos generales.

Una forma obvia y probablemente no eficiente es

 verts = [0 for x in range(1000)] 

Tenga en cuenta que esto se puede extender a 2 dimensiones fácilmente. Por ejemplo, para obtener una “matriz” de 10×100 puede hacer

 verts = [[0 for x in range(100)] for y in range(10)] 

Querer inicializar una matriz de tamaño fijo es algo perfectamente aceptable en cualquier lenguaje de progtwigción; no es como si el progtwigdor quisiera poner una instrucción break en un bucle while (true). Créanme, especialmente si los elementos solo se sobrescribirán y no simplemente se agregarán / restarán, como es el caso de muchos algoritmos de progtwigción dinámica, no desea perder el tiempo con las declaraciones adjuntas y verificar si el elemento no ha sido Inicializado todavía sobre la marcha (eso es un montón de codigos de código).

object = [0 for x in range(1000)]

Esto funcionará para lo que el progtwigdor está tratando de lograr.

@Steve ya dio una buena respuesta a tu pregunta:

 verts = [None] * 1000 

Advertencia: como lo señaló @Joachim Wuttke, la lista debe inicializarse con un elemento inmutable. [[]] * 1000 no funciona como se esperaba porque obtendrás una lista de 1000 listas idénticas (similar a una lista de 1000 puntos de la misma lista en C). Los objetos inmutables como int, str o tuple estarán bien.

Alternativas

Cambiar el tamaño de las listas es lento. Los siguientes resultados no son muy sorprendentes:

 >>> N = 10**6 >>> %timeit a = [None] * N 100 loops, best of 3: 7.41 ms per loop >>> %timeit a = [None for x in xrange(N)] 10 loops, best of 3: 30 ms per loop >>> %timeit a = [None for x in range(N)] 10 loops, best of 3: 67.7 ms per loop >>> a = [] >>> %timeit for x in xrange(N): a.append(None) 10 loops, best of 3: 85.6 ms per loop 

Pero el cambio de tamaño no es muy lento si no tienes listas muy grandes. En lugar de inicializar la lista con un solo elemento (por ejemplo, None ) y una longitud fija para evitar el cambio de tamaño de la lista, debe considerar el uso de la lista de comprensión y llenar directamente la lista con los valores correctos. Por ejemplo:

 >>> %timeit a = [x**2 for x in xrange(N)] 10 loops, best of 3: 109 ms per loop >>> def fill_list1(): """Not too bad, but complicated code""" a = [None] * N for x in xrange(N): a[x] = x**2 >>> %timeit fill_list1() 10 loops, best of 3: 126 ms per loop >>> def fill_list2(): """This is slow, use only for small lists""" a = [] for x in xrange(N): a.append(x**2) >>> %timeit fill_list2() 10 loops, best of 3: 177 ms per loop 

Comparacion con numpy

Para grandes conjuntos de datos, numpy u otras bibliotecas optimizadas son mucho más rápidas:

 from numpy import ndarray, zeros %timeit empty((N,)) 1000000 loops, best of 3: 788 ns per loop %timeit zeros((N,)) 100 loops, best of 3: 3.56 ms per loop 

Podrías hacer esto:

 verts = list(xrange(1000)) 

Eso le daría una lista de 1000 elementos en tamaño y que se inicializará con valores de 0-999. Como la list hace un __len__ primero para dimensionar la nueva lista, debería ser bastante eficiente.

Debería considerar usar un tipo dict lugar de una lista preinicializada. El costo de una búsqueda en el diccionario es pequeño y comparable al costo de acceder a un elemento de lista arbitrario.

Y cuando usas un mapeo puedes escribir:

 aDict = {} aDict[100] = fetchElement() putElement(fetchElement(), fetchPosition(), aDict) 

Y la función putElement puede almacenar artículos en cualquier posición dada. Y si necesita verificar si su colección contiene un elemento en el índice dado, es más Pythonic escribir:

 if anIndex in aDict: print "cool!" 

Que:

 if not myList[anIndex] is None: print "cool!" 

Dado que este último asume que ningún elemento real en su colección puede ser None . Y si eso sucede, tu código se comporta mal.

Y si necesita un rendimiento desesperado y es por eso que intenta preinicializar sus variables y escribir el código más rápido posible, cambie su idioma. El código más rápido no se puede escribir en Python. En su lugar, debería probar C e implementar envoltorios para llamar a su código preinicializado y precomstackdo desde Python.

Esta:

  lst = [8 for i in range(9)] 

Crea una lista, los elementos se inicializan 8.

pero esto:

 lst = [0] * 7 

crearía 7 listas que tienen un elemento

Sin saber más sobre el dominio del problema, es difícil responder a su pregunta. A menos que esté seguro de que necesita hacer algo más, la forma pythonica de inicializar una lista es:

 verts = []

¿Estás viendo realmente un problema de rendimiento? Si es así, ¿cuál es el cuello de botella de rendimiento? No trates de resolver un problema que no tienes. Es probable que el costo de rendimiento para llenar dinámicamente una matriz de 1000 elementos sea completamente irrelevante para el progtwig que realmente está intentando escribir.

La clase de matriz es útil si las cosas en su lista siempre van a ser un tipo de longitud fija primitiva específica (por ejemplo, char, int, float). Pero, tampoco requiere preinicialización.