在Python中将列表初始化为已知数量的元素

现在我正在使用一个列表,并期待类似的东西:

verts = list (1000)

我应该用数组代替吗?

675818 次浏览

我首先想到的是:

verts = [None]*1000

但是你真的需要初始化它吗?

如果不了解更多的问题领域,就很难回答你的问题。 除非你确定你需要做更多的事情,否则python化列表的方法是:

verts = []

你是否真的看到了性能问题?如果有,性能瓶颈是什么? 不要试图去解决一个你没有的问题。动态地将一个数组填充到1000个元素的性能代价很可能是你真正试图编写的程序的完全无关紧要的

数组类是有用的,如果你的列表中的东西总是一个特定的基本固定长度类型(例如char, int, float)。但是,它也不需要预初始化。

你应该考虑使用dict类型而不是预先初始化的列表。字典查找的开销很小,与访问任意列表元素的开销相当。

当使用映射时,你可以这样写:

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

putElement函数可以将item存储在任何给定位置。如果你需要检查你的集合是否包含给定索引的元素,那么更python化的做法是:

if anIndex in aDict:
print "cool!"

比:

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

因为后者假设集合中没有真正的元素可以是None。如果发生这种情况,你的代码就会出错。

如果你迫切需要性能,这就是为什么你试图预初始化你的变量,并编写尽可能快的代码-改变你的语言。最快的代码不能用Python编写。您应该尝试使用C语言,并实现包装器来从Python调用预初始化和预编译的代码。

你可以这样做:

verts = list(xrange(1000))

That would give you a list of 1000 elements in size and which happens to be initialised with values from 0-999. As list does a __len__ first to size the new list it should be fairly efficient.

不太清楚为什么每个人都给你这样做的困难时间-有几种情况下,你需要一个固定大小的初始化列表。你已经正确地推断出数组在这种情况下是可行的。

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

对于非python爱好者,(0,)*1000术语创建了一个包含1000个零的元组。逗号迫使python将(0)识别为元组,否则它将被求值为0。

我使用元组而不是列表,因为它们通常有更低的开销。

一个显而易见但可能并不有效的方法是

verts = [0 for x in range(1000)]
注意,这可以很容易地扩展到2维。 例如,要获得一个10x100的“数组”,您可以执行

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

在任何编程语言中,初始化固定大小的数组都是完全可以接受的事情;程序员并不想在while(true)循环中放入break语句。相信我,特别是当元素只是要被覆盖,而不仅仅是添加/减去,就像许多动态编程算法的情况一样,你不希望在附加语句和检查元素是否尚未初始化的情况下(这是大量的代码)。

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

这将为程序员试图实现的目标工作。

@Steve已经很好地回答了你的问题:

verts = [None] * 1000

正如@Joachim Wuttke指出的,列表必须用一个不可变元素初始化。[[]] * 1000不像预期的那样工作,因为你将得到一个包含1000个相同列表的列表(类似于C语言中包含1000个指向同一列表的点的列表)。int、str或tuple等不可变对象可以很好地工作。

选择

调整列表的大小很慢。以下结果并不令人惊讶:

>>> 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

但是如果您没有非常大的列表,那么调整大小并不会非常慢。与其使用单个元素(例如None)和固定长度来初始化列表以避免列表大小的调整,您应该考虑使用列表推导式并直接用正确的值填充列表。例如:

>>> %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

与numpy的比较

对于庞大的数据集,numpy或其他优化的库要快得多:

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

这样的:

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

创建一个列表,元素初始化8

但这:

lst = [0] * 7

会创建7个包含一个元素的列表吗