为什么[]比list()快?
最大的原因是Python将list()视为用户定义的函数,这意味着您可以通过将其他东西别名为list来拦截它,并做一些不同的事情(比如使用您自己的子类列表或deque)。
它立即使用[]创建一个内置列表的新实例。
我的解释是为了给你们一个直观的理解。
解释
[]通常被称为字面语法。
在语法中,这被称为“列表显示”。从文档中可以看出:
A list display is a possibly empty series of expressions enclosed in
square brackets:
list_display ::= "[" [starred_list | comprehension] "]"
A list display yields a new list object, the contents being specified
by either a list of expressions or a comprehension. When a
comma-separated list of expressions is supplied, its elements are
evaluated from left to right and placed into the list object in that
order. When a comprehension is supplied, the list is constructed from
the elements resulting from the comprehension.
简而言之,这意味着创建了一个list类型的内置对象。
这是无法避免的——这意味着Python可以尽可能快地做到这一点。
另一方面,list()可以在使用内置列表构造函数创建内置列表时被拦截。
例如,假设我们希望我们的列表创建噪音:
class List(list):
def __init__(self, iterable=None):
if iterable is None:
super().__init__()
else:
super().__init__(iterable)
print('List initialized.')
然后,我们可以在模块级别的全局作用域中拦截name列表,然后当我们创建一个列表时,我们实际上创建了我们的子类型列表:
>>> 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时,我们必须进行查找,看看是否有任何东西在那里。
然后我们必须调用我们查到的任何可调用对象。从语法来看:
一个调用调用一个可调用对象(例如,一个函数)
空参数系列:
调用::= 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()查找可调用对象,然后调用它。
而[]是一个列表显示,或一个文字,因此避免了名称查找和函数调用。