为了账号安全,请及时绑定邮箱和手机立即绑定

为什么列表理解比附加列表要快得多?

为什么列表理解比附加列表要快得多?

RISEBY 2019-10-12 09:32:10
我想知道为什么列表理解比附加到列表要快得多。我以为差异只是表达性的,不是。>>> import timeit >>> timeit.timeit(stmt='''\t = []for i in range(10000):    t.append(i)''', number=10000)9.467898777974142>>> timeit.timeit(stmt='t= [i for i in range(10000)]', number=10000)4.1138417314859列表理解速度提高了50%。为什么?
查看完整描述

3 回答

?
ITMISS

TA贡献1871条经验 获得超8个赞

列表理解基本上只是常规for循环的“语法糖” 。在这种情况下,它执行得更好的原因是因为它不需要加载列表的append属性并在每次迭代时都将其作为函数调用。换句话说,一般而言,列表理解的执行速度更快,因为挂起和恢复一个函数的框架(在其他情况下是多个函数)要比按需创建列表慢。


考虑以下示例:


# Python-3.6


In [1]: import dis


In [2]: def f1():

   ...:     l = []

   ...:     for i in range(5):

   ...:         l.append(i)

   ...:         


In [3]: def f2():

   ...:     [i for i in range(5)]

   ...:     


In [4]: dis.dis(f1)

  2           0 BUILD_LIST               0

              3 STORE_FAST               0 (l)


  3           6 SETUP_LOOP              33 (to 42)

              9 LOAD_GLOBAL              0 (range)

             12 LOAD_CONST               1 (5)

             15 CALL_FUNCTION            1 (1 positional, 0 keyword pair)

             18 GET_ITER

        >>   19 FOR_ITER                19 (to 41)

             22 STORE_FAST               1 (i)


  4          25 LOAD_FAST                0 (l)

             28 LOAD_ATTR                1 (append)

             31 LOAD_FAST                1 (i)

             34 CALL_FUNCTION            1 (1 positional, 0 keyword pair)

             37 POP_TOP

             38 JUMP_ABSOLUTE           19

        >>   41 POP_BLOCK

        >>   42 LOAD_CONST               0 (None)

             45 RETURN_VALUE


In [5]: dis.dis(f2)

  2           0 LOAD_CONST               1 (<code object <listcomp> at 0x7fe48b2265d0, file "<ipython-input-3-9bc091d521d5>", line 2>)

              3 LOAD_CONST               2 ('f2.<locals>.<listcomp>')

              6 MAKE_FUNCTION            0

              9 LOAD_GLOBAL              0 (range)

             12 LOAD_CONST               3 (5)

             15 CALL_FUNCTION            1 (1 positional, 0 keyword pair)

             18 GET_ITER

             19 CALL_FUNCTION            1 (1 positional, 0 keyword pair)

             22 POP_TOP

             23 LOAD_CONST               0 (None)

             26 RETURN_VALUE

您可以在偏移量22处看到我们append在第一个函数中有一个属性,因为使用列表推导在第二个函数中没有这样的东西。所有这些额外的字节码将使附加方法变慢。还要注意,append在每次迭代中还将加载属性,这会使您的代码比使用列表理解的第二个函数慢大约2倍的时间。


查看完整回答
反对 回复 2019-10-12
?
四季花海

TA贡献1811条经验 获得超5个赞

援引该文章,那是因为append的属性list没有抬头,加载并作为函数调用,这需要时间,并且在迭代加起来。


查看完整回答
反对 回复 2019-10-12
  • 3 回答
  • 0 关注
  • 253 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信