为什么[] 比list() 快?
最大的原因是 Python 将 list() 视为用户定义的函数,这意味着您可以通过将其他内容别名为 list 来拦截它并执行不同的操作(例如使用您自己的子类列表或者可能是双端队列) )。
它立即使用[] 创建一个内置列表的新实例。
我的解释旨在让您对此有直觉。
说明
[] 通常称为文字语法。
在语法中,这被称为“列表显示”。 From the docs:
列表显示是包含在
方括号:
list_display ::= "[" [starred_list | comprehension] "]"
列表显示产生一个新的列表对象,内容被指定
通过表达式列表或理解。当一个
提供逗号分隔的表达式列表,其元素是
从左到右评估并放入该列表对象中
命令。当提供推导时,列表由
理解产生的元素。
简而言之,这意味着创建了一个list 类型的内置对象。
没有办法规避这一点 - 这意味着 Python 可以尽可能快地做到这一点。
另一方面,list() 可以通过使用内置列表构造函数创建内置 list 被拦截。
例如,假设我们希望我们的列表被嘈杂地创建:
class List(list):
def __init__(self, iterable=None):
if iterable is None:
super().__init__()
else:
super().__init__(iterable)
print('List initialized.')
然后我们可以在模块级别的全局范围内拦截名称list,然后当我们创建list 时,我们实际上创建了子类型列表:
>>> list = List
>>> a_list = list()
List initialized.
>>> type(a_list)
<class '__main__.List'>
同样我们可以从全局命名空间中移除它
del list
并将其放入内置命名空间中:
import builtins
builtins.list = List
现在:
>>> list_0 = list()
List initialized.
>>> type(list_0)
<class '__main__.List'>
并注意列表显示无条件创建列表:
>>> list_1 = []
>>> type(list_1)
<class 'list'>
我们可能只是暂时这样做,所以让我们撤消我们的更改 - 首先从内置函数中删除新的 List 对象:
>>> del builtins.list
>>> builtins.list
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'builtins' has no attribute 'list'
>>> list()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'list' is not defined
哦,不,我们失去了原来的踪迹。
不用担心,我们仍然可以得到list - 它是列表文字的类型:
>>> builtins.list = type([])
>>> list()
[]
所以...
为什么[] 比list() 快?
正如我们所见——我们可以覆盖list——但我们不能拦截文字类型的创建。当我们使用list 时,我们必须进行查找以查看是否存在任何内容。
然后我们必须调用我们查找的任何可调用对象。从语法:
一个调用调用一个可调用对象(例如,一个函数)
一系列空参数:
call ::= primary "(" [argument_list [","] | comprehension] ")"
我们可以看到它对任何名称都做同样的事情,而不仅仅是列表:
>>> import dis
>>> dis.dis('list()')
1 0 LOAD_NAME 0 (list)
2 CALL_FUNCTION 0
4 RETURN_VALUE
>>> dis.dis('doesnotexist()')
1 0 LOAD_NAME 0 (doesnotexist)
2 CALL_FUNCTION 0
4 RETURN_VALUE
对于[],在 Python 字节码级别没有函数调用:
>>> dis.dis('[]')
1 0 BUILD_LIST 0
2 RETURN_VALUE
它只是直接构建列表,而无需在字节码级别进行任何查找或调用。
结论
我们已经证明list 可以使用范围规则被用户代码拦截,list() 会查找可调用对象然后调用它。
而[] 是列表显示或文字,因此避免了名称查找和函数调用。