如何在python中创建修复大小列表?

wtm*_*wtm 46 python list

在C++中,我可以创建一个像...一样的数组

int* a = new int[10];
Run Code Online (Sandbox Code Playgroud)

在python中,我只知道我可以声明一个列表,而不是追加一些项目,或者像...

l = [1,2,3,4]
l = range(10)
Run Code Online (Sandbox Code Playgroud)

我可以按照给定的大小初始化列表,比如c ++,不做任何分配吗?

nin*_*cko 57

(tl;博士:你的问题的确切答案是numpy.emptynumpy.empty_like,但你可能不在乎,可以逃脱使用myList = [None]*10000.)

简单的方法

您可以将列表初始化为所有相同的元素.在语义上是否有意义使用非数字值(如果你使用它会产生错误,这是一件好事)或类似0(不寻常?如果你正在编写稀疏矩阵或'默认'值应为0,您不担心错误)取决于您:

>>> [None for _ in range(10)]
[None, None, None, None, None, None, None, None, None, None]
Run Code Online (Sandbox Code Playgroud)

(这里_只是一个变量名,您可以使用i.)

你也可以这样做:

>>> [None]*10
[None, None, None, None, None, None, None, None, None, None]
Run Code Online (Sandbox Code Playgroud)

您可能不需要优化它.您还可以在每次需要时附加到数组:

>>> x = []
>>> for i in range(10):
>>>    x.append(i)
Run Code Online (Sandbox Code Playgroud)

简单方法的性能比较

哪个最好?

>>> 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)
Run Code Online (Sandbox Code Playgroud)

python2.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
Run Code Online (Sandbox Code Playgroud)

python 3.2中的结果:

initAndWrite_test takes 641.3581371307373 usec/loop
initAndWrite2_test takes 1033.6499214172363 usec/loop
appendWrite_test takes 895.9040641784668 usec/loop
Run Code Online (Sandbox Code Playgroud)

我们可以看到,[None]*10000在python2和python3中做成语可能更好.但是,如果一个人做了比赋值更复杂的事情(例如生成或处理列表中每个元素的任何复杂事件),那么开销就变成了成本的无意义的一小部分.也就是说,如果您对列表中的元素做了任何合理的事情,这种优化还为时过早.


未初始化的内存

然而,这些都是低效的,因为它们通过记忆,在过程中写一些东西.在C中,这是不同的:未初始化的数组中充满了随机垃圾内存(旁注:已从系统重新分配,当您在关闭程序时分配或未能进行mlock和/或无法删除内存时可能存在安全风险).这是一个设计选择,专为加速而设计:C语言的制造者认为最好不要自动初始化内存,这是正确的选择.

这不是渐近加速(因为它是O(N)),但是例如,在用你真正关心的东西覆盖之前,你不需要首先初始化你的整个内存块.如果可能的话,这等同于(伪代码)x = list(size=10000).

如果你想在python中有类似的东西,你可以使用numpy数值矩阵/ N维数组操作包.具体来说,numpy.emptynumpy.empty_like

这是你问题的真正答案.

  • `x = [[None]]*10` 是“错误的”。试试 `x[0].append(1)` 看看神奇之处。 (2认同)

jad*_*k94 7

你可以用这个:[None] * 10.但这不是"固定大小"你仍然可以附加,删除......这就是列表的制作方式.

你可以使它成为一个元组(tuple([None] * 10))来修复它的宽度,但同样,你将无法改变它(不是在所有情况下,只有当存储的项目是可变的时).

另一个选项,更接近您的要求,不是列表,而是collections.deque具有最大长度的列表.这是最大尺寸,但可能更小.

import collections
max_4_items = collections.deque([None] * 4, maxlen=4)
Run Code Online (Sandbox Code Playgroud)

但是,只需使用一个列表,并习惯"pythonic"的做事方式.


Vla*_*den 6

您可以使用数组模块来完成。数组模块是python标准库的一部分:

from array import array
from itertools import repeat

a = array("i", repeat(0, 10))
# or
a = array("i", [0]*10)
Run Code Online (Sandbox Code Playgroud)

重复功能将 0 值重复 10 次。它比 [0]*10 的内存效率更高,因为它不分配内存,而是重复返回相同数量的 x 次。


Rol*_*ony 6

这与其说是回答,不如说是警告。
在其他答案中看到后my_list = [None] * 10,我很受诱惑并设置了这样的数组speakers = [['','']] * 10,并且非常后悔,因为结果list并没有像我想象的那样表现。
我求助于:

speakers = []
for i in range(10):
    speakers.append(['',''])
Run Code Online (Sandbox Code Playgroud)

由于[['','']] * 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']]
Run Code Online (Sandbox Code Playgroud)

而有.append选项:

>>> n=[]
>>> for i in range(10):
...  n.append(['',''])
... 
>>> n
[['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', '']]
>>> n[0][0] = "abc"
>>> n
[['abc', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', '']]
>>> n[0][1] = "True"
>>> n
[['abc', 'True'], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', ''], ['', '']]
Run Code Online (Sandbox Code Playgroud)

我确信 ninjagecko 接受的答案确实试图提及这一点,遗憾的是我太厚了无法理解。
结束,保重!

  • `[expr] * n` 将计算 `expr`,然后使用该值创建一个 `n` 元素列表。至关重要的是,“expr”仅被评估一次。如果“expr”计算为不可变值,那么这很好,但如果它计算为可变值,则绝对不是您想要的,因为每个元素都会指向同一个对象。在这种情况下,您真正​​想要的是对每个元素评估一次“expr”。Pythonic 解决方案是“[expr for _ in range(n)]”,因此在本例中为“[['',''] for _ in range(10)]”。 (2认同)