要在现有列表中复制嵌套列表,不幸的是,简单地将它相乘是不够的,否则会创建引用而不是列表中的独立列表,请参见以下示例:
x = [[1, 2, 3]] * 2
x[0] is x[1] # will evaluate to True
为了实现您的目标,您可以在列表理解中使用范围函数,例如,请参见:
x = [[1, 2, 3] for _ in range(2)]
x[0] is x[1] # will evaluate to False (wanted behaviour)
这是在不创建引用的情况下增加列表中项目的好方法,这在许多不同的网站上也有多次解释。
但是,有一种更有效的方法来复制列表元素。该代码对我来说似乎有点快(通过命令行通过 timeit 测量,并且对于下面的代码使用不同的参数 n ∈ {1, 50, 100, 10000} 并且在上面的代码中使用 range(n)):
x = [[1, 2, 3] for _ in [0] * n]
但我想知道,为什么这段代码运行得更快?还有其他缺点吗(更多的内存消耗或类似的)?
python -m timeit '[[1, 2, 3] for _ in range(1)]'
1000000 loops, best of 3: 0.243 usec per loop
python -m timeit '[[1, 2, 3] for _ in range(50)]'
100000 loops, best of 3: 3.79 usec per loop
python -m timeit '[[1, 2, 3] for _ in range(100)]'
100000 loops, best of 3: 7.39 usec per loop
python -m timeit '[[1, 2, 3] for _ in range(10000)]'
1000 loops, best of 3: 940 usec per loop
python -m timeit '[[1, 2, 3] for _ in [0] * 1]'
1000000 loops, best of 3: 0.242 usec per loop
python -m timeit '[[1, 2, 3] for _ in [0] * 50]'
100000 loops, best of 3: 3.77 usec per loop
python -m timeit '[[1, 2, 3] for _ in [0] * 100]'
100000 loops, best of 3: 7.3 usec per loop
python -m timeit '[[1, 2, 3] for _ in [0] * 10000]'
1000 loops, best of 3: 927 usec per loop
# difference will be greater for larger n
python -m timeit '[[1, 2, 3] for _ in range(1000000)]'
10 loops, best of 3: 144 msec per loop
python -m timeit '[[1, 2, 3] for _ in [0] * 1000000]'
10 loops, best of 3: 126 msec per loop
最佳答案
这是正确的; range
,即使在生成紧凑范围对象的 Python 3 中,在计算和存储之间的经典权衡中也比列表更复杂。
随着列表变得太大而无法放入缓存(如果我们关心性能,这就是首要问题),范围对象遇到了一个不同的问题:当范围中的每个数字被创建时,它会销毁并创建新的 int
对象(前 256 个左右的成本较低,因为它们被保留了,但它们的差异仍然会导致一些缓存未命中)。该列表将继续引用同一个列表。
不过,还有更有效的选择;例如,bytearray 消耗的内存要比列表少得多。该任务的最佳功能可能隐藏在 itertools
中:repeat
.与范围对象一样,它不需要存储所有副本,但与重复列表一样,它不需要创建不同的对象。因此,像 for _ in repeat(None, x)
这样的东西只会戳相同的几个缓存行(对象的迭代计数和引用计数)。
最后,人们坚持使用 range
的主要原因是因为它是突出显示的内容(在固定计数循环的习惯用法和内置函数中)。
在其他 Python 实现中,range 很可能比 repeat 更快;这是因为计数器本身已经拥有该值。我期待 Cython 或 PyPy 的这种行为。
关于python - 为什么 range() 函数比乘法项目慢以获取嵌套列表中的副本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50838886/