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

为什么[]比list()快?

为什么[]比list()快?

FFIVE 2019-09-27 16:33:56
我最近比较了[]和的处理速度,并list()惊讶地发现它的[]运行速度是的三倍以上list()。我跑了相同的测试与{}和dict(),结果几乎相同:[]和{}两个花了大约0.128sec /百万次,而list()和dict()大约花费每个0.428sec /万次。为什么是这样?不要[]和{}(可能()和'',太)立即传回文字的一些空股票的份,而其明确命名同行(list(),dict(),tuple(),str())完全去创建一个对象,他们是否真的有元素?我不知道这两种方法有何不同,但我很想找出答案。我在文档中或SO上都找不到答案,而寻找空括号却比我预期的要麻烦得多。通过分别调用timeit.timeit("[]")和timeit.timeit("list()"),和timeit.timeit("{}")和timeit.timeit("dict()")来比较列表和字典,以获得计时结果。我正在运行Python 2.7.9。我最近发现“ 为什么True慢于if? ”比较了if Trueto 的性能,if 1并且似乎触及了类似的文字对全局场景;也许也值得考虑。
查看完整描述

3 回答

?
拉莫斯之舞

TA贡献1820条经验 获得超10个赞

因为[]和{}是文字语法。Python可以创建字节码仅用于创建列表或字典对象:


>>> import dis

>>> dis.dis(compile('[]', '', 'eval'))

  1           0 BUILD_LIST               0

              3 RETURN_VALUE        

>>> dis.dis(compile('{}', '', 'eval'))

  1           0 BUILD_MAP                0

              3 RETURN_VALUE        

list()和dict()是单独的对象。它们的名称需要解析,必须包含堆栈以推入参数,必须存储框架以供以后检索,并且必须进行调用。这都需要更多时间。


对于空的情况,这意味着您至少要有一个LOAD_NAME(必须在全局名称空间以及__builtin__模块中进行搜索),后跟一个CALL_FUNCTION必须保留当前帧:


>>> dis.dis(compile('list()', '', 'eval'))

  1           0 LOAD_NAME                0 (list)

              3 CALL_FUNCTION            0

              6 RETURN_VALUE        

>>> dis.dis(compile('dict()', '', 'eval'))

  1           0 LOAD_NAME                0 (dict)

              3 CALL_FUNCTION            0

              6 RETURN_VALUE        

您可以使用以下命令分别计时名称查找timeit:


>>> import timeit

>>> timeit.timeit('list', number=10**7)

0.30749011039733887

>>> timeit.timeit('dict', number=10**7)

0.4215109348297119

时间差异可能是字典哈希冲突。从调用这些对象的时间中减去这些时间,然后将结果与使用文字的时间进行比较:


>>> timeit.timeit('[]', number=10**7)

0.30478692054748535

>>> timeit.timeit('{}', number=10**7)

0.31482696533203125

>>> timeit.timeit('list()', number=10**7)

0.9991960525512695

>>> timeit.timeit('dict()', number=10**7)

1.0200958251953125

因此,1.00 - 0.31 - 0.30 == 0.39每1000万次调用必须调用该对象花费了额外的几秒钟。


您可以通过将全局名称别名为本地名称来避免全局查找成本(使用timeit设置,绑定到名称的所有内容都是本地名称):


>>> timeit.timeit('_list', '_list = list', number=10**7)

0.1866450309753418

>>> timeit.timeit('_dict', '_dict = dict', number=10**7)

0.19016098976135254

>>> timeit.timeit('_list()', '_list = list', number=10**7)

0.841480016708374

>>> timeit.timeit('_dict()', '_dict = dict', number=10**7)

0.7233691215515137

但您永远无法克服这些CALL_FUNCTION成本。


查看完整回答
反对 回复 2019-09-27
?
慕尼黑8549860

TA贡献1818条经验 获得超11个赞

list()需要全局查找和函数调用,但需要[]编译为一条指令。看到:


Python 2.7.3

>>> import dis

>>> print dis.dis(lambda: list())

  1           0 LOAD_GLOBAL              0 (list)

              3 CALL_FUNCTION            0

              6 RETURN_VALUE        

None

>>> print dis.dis(lambda: [])

  1           0 BUILD_LIST               0

              3 RETURN_VALUE        

None


查看完整回答
反对 回复 2019-09-27
?
守着星空守着你

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

因为list是一个功能转化说一个字符串列表对象,而[]用于创建一个列表蝙蝠。尝试一下(可能对您更有意义):


x = "wham bam"

a = list(x)

>>> a

["w", "h", "a", "m", ...]


y = ["wham bam"]

>>> y

["wham bam"]

为您提供包含您所输入内容的实际列表。


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

添加回答

举报

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