为什么从生成器表达式创建元组比从列表推导式创建元组慢?
Why is making a tuple from a generator expression slower than making one from a list comprehension?
(此问题基于现已删除的推文)
我 运行 以下同时包含 Python3.9 和 Python3.10:
$ python -m timeit 'tuple([-x for x in range(1000)])'
10000 loops, best of 5: 35.7 usec per loop
$ python -m timeit 'tuple(-x for x in range(1000))'
5000 loops, best of 5: 45.7 usec per loop
令人惊讶的是,构建额外对象(列表)的版本更快。为什么会这样?如果这确实更快,为什么元组构造函数不只是在后台实例化一个列表?
注意:我还为长度为 10 和长度为 100 万的元组计时,并且带有列表的版本总是更快。
试试这个:
python -m timeit 'list(-x for x in range(1000))'
我预测您会发现它花费的时间与您的:
python -m timeit 'tuple(-x for x in range(1000))'
还有那个
python -m timeit 'list([-x for x in range(1000)])'
将再次恢复“丢失”的速度。
这是因为列表与元组实际上无关。相反,tuple()
和 list()
只是对 Python 的函数调用,并且可以调用任何东西(默认情况下,这些名称绑定到内置函数,但用户可以重新绑定它们任何事情)。
但是[expression for vrb in ...]
是专用的语法,其含义用户代码不能改变。 Python 在编译时知道它正在构建一个列表,并生成特殊代码来利用它。该代码根本不会调用 list()
,而是直接自己构建列表,一次一个元素。实际上没有构建生成器表达式,并且从生成器表达式一次生成一个元素也没有开销。
构建包含这些表达式的简单函数,并使用dis.dis()
显示生成的字节码。代码非常不同:-)
(此问题基于现已删除的推文)
我 运行 以下同时包含 Python3.9 和 Python3.10:
$ python -m timeit 'tuple([-x for x in range(1000)])'
10000 loops, best of 5: 35.7 usec per loop
$ python -m timeit 'tuple(-x for x in range(1000))'
5000 loops, best of 5: 45.7 usec per loop
令人惊讶的是,构建额外对象(列表)的版本更快。为什么会这样?如果这确实更快,为什么元组构造函数不只是在后台实例化一个列表?
注意:我还为长度为 10 和长度为 100 万的元组计时,并且带有列表的版本总是更快。
试试这个:
python -m timeit 'list(-x for x in range(1000))'
我预测您会发现它花费的时间与您的:
python -m timeit 'tuple(-x for x in range(1000))'
还有那个
python -m timeit 'list([-x for x in range(1000)])'
将再次恢复“丢失”的速度。
这是因为列表与元组实际上无关。相反,tuple()
和 list()
只是对 Python 的函数调用,并且可以调用任何东西(默认情况下,这些名称绑定到内置函数,但用户可以重新绑定它们任何事情)。
但是[expression for vrb in ...]
是专用的语法,其含义用户代码不能改变。 Python 在编译时知道它正在构建一个列表,并生成特殊代码来利用它。该代码根本不会调用 list()
,而是直接自己构建列表,一次一个元素。实际上没有构建生成器表达式,并且从生成器表达式一次生成一个元素也没有开销。
构建包含这些表达式的简单函数,并使用dis.dis()
显示生成的字节码。代码非常不同:-)