首页 > 解决方案 > 解包 vs for 循环以打印列表中的元素

问题描述

我正在使用 Python 解决一些练习题,在其中一个问题中,我必须遍历一个数字列表并将每个元素打印在单独的行上。

在我的第一次尝试中,我尝试这样做:

nums = [1, 2, 3, 4, 5 ...with more numbers]

for num in nums:
  print(num)

这使我能够通过该问题的测试用例,但我很好奇其他人是如何处理该问题的,因此查看了他们的一些解决方案。

我注意到有人正在使用解包操作符来实现与我上面的 for 循环相同的事情,如下所示:

print(*nums, sep='\n')

当我执行上面使用解包操作符的代码时,我注意到脚本的执行时间增加了约 50%。

当然,这可能是由于其他因素造成的,但我的清单的拆包是否有可能对性能产生影响?

如果确实如此,为什么会这样?

标签: python

解决方案


我在 macOS(版本 10.15.7,2.5 GHz 双核 Intel Core i5)上使用 Python 3.9.1 测试了这两个代码,发现性能上有任何显着差异。

首先,我检查了 CPython 字节码:

>>> import dis
>>>
>>> code1 = """\
... nums = list(range(1000))
...
... for num in nums:
...     print(num)
... """
>>> code2 = """\
... nums = list(range(1000))
... print(*nums, sep='\\n')
... """
>>>
>>> dis.dis(code1)
  1           0 LOAD_NAME                0 (list)
              2 LOAD_NAME                1 (range)
              4 LOAD_CONST               0 (1000)
              6 CALL_FUNCTION            1
              8 CALL_FUNCTION            1
             10 STORE_NAME               2 (nums)

  2          12 LOAD_NAME                2 (nums)
             14 GET_ITER
        >>   16 FOR_ITER                12 (to 30)
             18 STORE_NAME               3 (num)

  3          20 LOAD_NAME                4 (print)
             22 LOAD_NAME                3 (num)
             24 CALL_FUNCTION            1
             26 POP_TOP
             28 JUMP_ABSOLUTE           16
        >>   30 LOAD_CONST               1 (None)
             32 RETURN_VALUE
>>> dis.dis(code2)
  1           0 LOAD_NAME                0 (list)
              2 LOAD_NAME                1 (range)
              4 LOAD_CONST               0 (1000)
              6 CALL_FUNCTION            1
              8 CALL_FUNCTION            1
             10 STORE_NAME               2 (nums)

  2          12 LOAD_NAME                3 (print)
             14 LOAD_NAME                2 (nums)
             16 LOAD_CONST               1 ('sep')
             18 LOAD_CONST               2 ('\n')
             20 BUILD_MAP                1
             22 CALL_FUNCTION_EX         1
             24 POP_TOP
             26 LOAD_CONST               3 (None)
             28 RETURN_VALUE

正如您在第二个代码中看到的那样,列表没有被解包(LOAD_NAME print, LOADNAME numvs LOAD_NAME print, LOADNAME nums)。

另外,我什至timeit它:

from timeit import timeit

def f1():
    nums = list(range(1000))

    for num in nums:
        print(num)

def f2():
    nums = list(range(1000))
    print(*nums, sep='\n')

print(timeit(f1, number=20000))
print(timeit(f2, number=20000))

并得到了非常相似的结果(397.45 对 399.58 秒)。


推荐阅读