在 C++ 中,我可以像这样创建一个数组...
int* a = new int[10];
在Python中,我只知道可以声明一个列表,然后添加一些项目,或者类似于...
l = [1,2,3,4]
l = range(10)
我能否像C++一样按给定大小初始化列表,而不做任何赋值操作?
(简而言之,回答你问题的确切方法是numpy.empty
或numpy.empty_like
,但你可能不在乎,可以使用myList = [None]*10000
。)
您可以将列表初始化为相同的元素。是否在语义上使用非数字值(如果您使用它会导致错误,这是一件好事)或类似于0的东西(不寻常?也许在编写稀疏矩阵或“默认”值应该是0的情况下有用,并且您不担心错误)取决于您:
>>> [None for _ in range(10)]
[None, None, None, None, None, None, None, None, None, None]
(这里 _
只是一个变量名,你可以使用 i
。)
你也可以像这样做:
>>> [None]*10
[None, None, None, None, None, None, None, None, None, None]
你可能不需要对此进行优化。每次需要时,也可以将新的元素附加到数组末尾:
>>> x = []
>>> for i in range(10):
>>> x.append(i)
哪个方法最好?
>>> def initAndWrite_test():
... x = [None]*10000
... for i in range(10000):
... x[i] = i
...
>>> def initAndWrite2_test():
... x = [None for _ in range(10000)]
... for i in range(10000):
... x[i] = i
...
>>> def appendWrite_test():
... x = []
... for i in range(10000):
... x.append(i)
在Python 2.7中的结果:
>>> import timeit
>>> for f in [initAndWrite_test, initAndWrite2_test, appendWrite_test]:
... print('{} takes {} usec/loop'.format(f.__name__, timeit.timeit(f, number=1000)*1000))
...
initAndWrite_test takes 714.596033096 usec/loop
initAndWrite2_test takes 981.526136398 usec/loop
appendWrite_test takes 908.597946167 usec/loop
Python 3.2 的结果:
initAndWrite_test takes 641.3581371307373 usec/loop
initAndWrite2_test takes 1033.6499214172363 usec/loop
appendWrite_test takes 895.9040641784668 usec/loop
从python2和python3的角度来看,使用 [None]*10000
这个习惯用法可能更好。但是,如果要做的事情比赋值(例如生成或处理列表中的每个元素)更复杂,则开销成为总花费中无意义的一小部分。也就是说,如果你正在对列表元素进行任何合理操作,这样的优化是不必担心的。
然而,所有这些方法都很低效,因为它们通过内存,写入一些内容。在C语言中,这是不同的:一个未初始化的数组会被填充与随机垃圾内存(旁注:已经从系统重新分配,当您在关闭程序时分配或未能mlock和/或删除内存时,这可能是一个安全风险)。这是一种设计选择,旨在加速:C语言的创造者认为不自动初始化内存更好,并且这是正确的选择。
这不是渐进性加速(因为它是O(N)
),但例如,在覆盖实际关心的东西之前,您不需要首先初始化整个内存块。这相当于(伪代码)x = list(size=10000)
,如果可能的话。
如果您想在Python中实现类似的操作,可以使用 numpy
数值矩阵/多维数组操作包。具体而言,numpy.empty
或 numpy.empty_like
。
这就是您问题的真正答案。
x = [[None]]*10
是“错误的”。尝试x[0].append(1)
并看看魔法。 - Amit Tripathi[None] * 10
。但是这不会是“固定大小”,你仍然可以添加、删除... 这就是列表的制作方式。tuple([None] * 10)
)以固定宽度,但同样地,你将无法更改它(并非所有情况,只有存储的项目为可变时)。collections.deque
。它是最大尺寸,但它可以更小。import collections
max_4_items = collections.deque([None] * 4, maxlen=4)
不过,只需使用列表,并习惯于“Pythonic”做事的方式。
deque
不允许你从列表中间弹出一个元素。 - Jonathan这更像是一个警告而不是一个答案。
在看到其他答案中my_list = [None] * 10
的写法后,我也尝试了一下用speakers = [['','']] * 10
这样的方式生成一个数组,但最终结果并不如预期地运行。
最终我做出了以下修改:
speakers = []
for i in range(10):
speakers.append(['',''])
[['','']] * 10
看起来创建了一个 list
,其中后续元素是第一个元素的副本。
例如:
>>> n=[['','']]*10
>>> n
[['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', '']]
>>> n[0][0] = "abc"
>>> n
[['abc', ''], ['abc', ''], ['abc', ''], ['abc', ''], ['abc', ''], ['abc', ''], ['abc', ''], ['abc', ''], ['abc', ''], ['abc', '']]
>>> n[0][1] = "True"
>>> n
[['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True'], ['abc', 'True']]
相对于使用.append
选项:
>>> n=[]
>>> for i in range(10):
... n.append(['',''])
...
>>> n
[['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', '']]
>>> n[0][0] = "abc"
>>> n
[['abc', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', '']]
>>> n[0][1] = "True"
>>> n
[['abc', 'True'], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', '']]
我确信ninjagecko所提供的被接受的答案试图提到这一点,但可惜我太蠢了无法理解。总之,保重!
[expr] * n
将会计算 expr
,然后使用该值创建一个包含 n
个元素的列表。需要注意的是,expr
只会被计算一次。如果 expr
计算出来的是不可变值,那么这种方式就没问题了。但如果它计算出来的是可变值,那么每个元素都会指向同一个对象,这显然不是我们想要的结果。在这种情况下,你需要让 expr
对每个元素都计算一次。Pythonic 的解决方案是 [expr for _ in range(n)]
,所以在这个例子中应该写成 [['',''] for _ in range(10)]
。 - Kevin这种初始化列表的方式并不是Python的惯用方式。不过,你可以像这样初始化一个列表:
>>> l = [None] * 4
>>> l
[None, None, None, None]
from numpy import *
l = zeros(10)
from numpy import *
会将Python内置的函数all
、abs
、min
、max
、sum
、any
和round
替换为NumPy中的等效函数,这可能并非您想要的结果。请注意使用。 - Lauritz V. Thaulownumpy
模块包含相当多的名称(当您编写数组代码时,在模块命名空间中拥有这些名称仍然很方便)。如果可能的名称冲突给您带来麻烦,请使用限定导入。 - ulidtkoPython没有内置支持此功能的方法。如果您不认为添加元素会带来太多开销,那么您真的需要如此优化吗?
但是,您可以使用类似于l = [None] * 1000
的方法。
或者,您可以使用生成器。
fix_array = numpy.empty(n, dtype = object)
n表示您的数组的大小。
虽然它可以工作,但这可能不是最好的想法,因为您需要导入一个库来实现此目的。希望这可以帮助到您!
your_list = [None]*size_required
range(10)
实际上是一个生成器对象;您将无法更改它。您需要使用list(range(10))
来进行操作。 - ninjagecko