Skip to the content.

Python中什么时候不使用List


Contact me:

Blog -> https://cugtyt.github.io/blog/index
Email -> cugtyt@qq.com
GitHub -> Cugtyt@GitHub


List是python中非常方便,使用度极高的容器,基本上任何需要序列存储的时候都可以用,但是,有些时候我们应该有不同的选择。

例如,你需要存储100万的浮点数,array就更加合适,因为它更节省空间,存储的是数值,而不是float的对象。

import numpy as np
from array import array
import sys

num_list = [float(i) for i in range(10**6)]
num_array = array('d', (i for i in range(10**6)))
num_np = np.array([np.float(i) for i in range(10**6)])

print(sys.getsizeof(num_list))
print(sys.getsizeof(num_array))
print(sys.getsizeof(num_np))

输出为:

8697464
8183800
8000096

注意到如果除去必须的存储空间8000000,三者额外需要的空间为:697464,183800,96,那么array比list少26%以上的空间,如果可以使用numpy的话,惊人的我们可以只需要96的额外空间,所以numpy更加推荐。

如果程序中需要大量的查询,例如item in my_collection,那么使用set更加高效:

from time import time

nums_list = [i for i in range(10**4) if i % 3 == 0]
start = time()
for i in range(10**4):
    i in nums_list
print(time() - start)

nums_set = set(i for i in range(10**4) if i % 3 == 0)
start = time()
for i in range(10**4):
    i in nums_set
print(time() - start)

输出为:

0.5104689598083496
0.015645265579223633

时间基本上是1/50的差别,可见,set的查询要高效很多,因为set为查询的操作有专门的优化。

另一个有趣的东西是merroyview,我们知道python隐藏了很多和内存直接相关的操作,如果我们希望用更加底层的方式操作集合,那么可以考虑使用它:

>>> numbers = array('h', [-2, -1, 0, 1, 2])
>>> memv = memoryview(numbers)
>>> len(memv)
5
>>> memv[0]
-2
>>> memv_oct = memv.cast('B')
[254, 255, 255, 255, 0, 0, 1, 0, 2, 0]
>>> memv_oct[5] = 4
>>> numbers
array('h', [-2, -1, 1024, 1, 2])

注意之所以变成1024是因为4的赋值导致原来的0变成了10_00000000。这需要一点关于内存模型的知识。