我在三个不同版本的CPython中测试了list(x for x in a)
。对于a = [0]
,它比a = []
快得多:
3.9.0 64-bit 3.9.0 32-bit 3.7.8 64-bit
a = [] a = [0] a = [] a = [0] a = [] a = [0]
465 ns 412 ns 543 ns 515 ns 513 ns 457 ns
450 ns 406 ns 544 ns 515 ns 506 ns 491 ns
456 ns 408 ns 551 ns 513 ns 515 ns 487 ns
455 ns 413 ns 548 ns 516 ns 513 ns 491 ns
452 ns 404 ns 549 ns 511 ns 508 ns 486 ns
使用 tuple
而不是 list
,结果会相反:
3.9.0 64-bit 3.9.0 32-bit 3.7.8 64-bit
a = [] a = [0] a = [] a = [0] a = [] a = [0]
354 ns 405 ns 467 ns 514 ns 421 ns 465 ns
364 ns 407 ns 467 ns 527 ns 425 ns 464 ns
353 ns 399 ns 490 ns 549 ns 419 ns 465 ns
352 ns 400 ns 500 ns 556 ns 414 ns 474 ns
354 ns 405 ns 494 ns 560 ns 420 ns 474 ns
那么为什么当list
(以及底层的生成器迭代器)需要执行更多操作时,它会更快呢?
在 Windows 10 Pro 2004 64 位上进行测试。
基准测试代码:
from timeit import repeat
setups = 'a = []', 'a = [0]'
number = 10**6
print(*setups, sep=' ')
for _ in range(5):
for setup in setups:
t = min(repeat('list(x for x in a)', setup, number=number)) / number
print('%d ns' % (t * 1e9), end=' ')
print()
字节大小,显示它不会为输入[]
过度分配空间,但对于输入[0]
则会:
>>> [].__sizeof__()
40
>>> list(x for x in []).__sizeof__()
40
>>> [0].__sizeof__()
48
>>> list(x for x in [0]).__sizeof__()
72
list
仅会分配足以容纳迭代器中元素的空间。元组由于无法增长,因此始终只分配足以容纳迭代器中内容的空间。 - chepnerlist(x for x in []).__sizeof__()
显示为 40 字节,而list(x for x in [0]).__sizeof__()
则显示为 72 字节。 - Kelly Bundy[]
更快,有时[0]
更快。 - Ocaso Protal[]
的执行时间比[0]
长大约两倍。 - Pranav Hosangadi[]: 463 ns ± 2.69 ns每次循环(15次运行的平均值±标准差,每次10000000个循环)
和[0]: 471 ns ± 3.4 ns每次循环(15次运行的平均值±标准差,每次10000000个循环)
。您还应该检查标准差,以确保您的结果不会有太大的变化。此外,请提供有关如何获得这些Python分布的详细信息。 - a_guest