在Python 3中,列表理解是否只是馈给list
函数的生成器表达式的语法糖?
例如下面的代码:
squares = [x**2 for x in range(1000)]
实际在后台转换为以下内容?
squares = list(x**2 for x in range(1000))
我知道输出是相同的,Python
3修复了列出理解的周围名称空间的令人惊讶的副作用,但是就CPython解释器的作用而言,是前者转换为后者,还是有任何区别?代码如何执行?
我在此问题的评论部分找到了这种对等的主张,而谷歌的快速搜索显示此处也提出了同样的主张。
“ Python 3.0的新增功能”文档中也提到了这一点,但措辞有些含糊:
还要注意,列表理解具有不同的语义:对于list()构造函数内的生成器表达式,它们更接近语法糖,并且尤其是循环控制变量不再泄漏到周围的范围中。
两者的工作方式不同。该列表理解的版本需要特殊的字节码的优势,LIST_APPEND
这就要求PyList_Append
直接给我们。因此,它避免了list.append
在Python级别进行属性查找和函数调用。
>>> def func_lc():
[x**2 for x in y]
...
>>> dis.dis(func_lc)
2 0 LOAD_CONST 1 (<code object <listcomp> at 0x10d3c6780, file "<ipython-input-42-ead395105775>", line 2>)
3 LOAD_CONST 2 ('func_lc.<locals>.<listcomp>')
6 MAKE_FUNCTION 0
9 LOAD_GLOBAL 0 (y)
12 GET_ITER
13 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
16 POP_TOP
17 LOAD_CONST 0 (None)
20 RETURN_VALUE
>>> lc_object = list(dis.get_instructions(func_lc))[0].argval
>>> lc_object
<code object <listcomp> at 0x10d3c6780, file "<ipython-input-42-ead395105775>", line 2>
>>> dis.dis(lc_object)
2 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 16 (to 25)
9 STORE_FAST 1 (x)
12 LOAD_FAST 1 (x)
15 LOAD_CONST 0 (2)
18 BINARY_POWER
19 LIST_APPEND 2
22 JUMP_ABSOLUTE 6
>> 25 RETURN_VALUE
另一方面,list()
版本仅将生成器对象传递给list的__init__
方法,然后在extend
内部调用其方法。由于对象不是列表或元组,因此CPython首先获取其迭代器,然后简单地将项目添加到列表中,直到迭代器用尽:
>>> def func_ge():
list(x**2 for x in y)
...
>>> dis.dis(func_ge)
2 0 LOAD_GLOBAL 0 (list)
3 LOAD_CONST 1 (<code object <genexpr> at 0x10cde6ae0, file "<ipython-input-41-f9a53483f10a>", line 2>)
6 LOAD_CONST 2 ('func_ge.<locals>.<genexpr>')
9 MAKE_FUNCTION 0
12 LOAD_GLOBAL 1 (y)
15 GET_ITER
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
19 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
22 POP_TOP
23 LOAD_CONST 0 (None)
26 RETURN_VALUE
>>> ge_object = list(dis.get_instructions(func_ge))[1].argval
>>> ge_object
<code object <genexpr> at 0x10cde6ae0, file "<ipython-input-41-f9a53483f10a>", line 2>
>>> dis.dis(ge_object)
2 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 15 (to 21)
6 STORE_FAST 1 (x)
9 LOAD_FAST 1 (x)
12 LOAD_CONST 0 (2)
15 BINARY_POWER
16 YIELD_VALUE
17 POP_TOP
18 JUMP_ABSOLUTE 3
>> 21 LOAD_CONST 1 (None)
24 RETURN_VALUE
>>>
时序比较:
>>> %timeit [x**2 for x in range(10**6)]
1 loops, best of 3: 453 ms per loop
>>> %timeit list(x**2 for x in range(10**6))
1 loops, best of 3: 478 ms per loop
>>> %%timeit
out = []
for x in range(10**6):
out.append(x**2)
...
1 loops, best of 3: 510 ms per loop
由于属性查找缓慢,因此正常循环会稍慢。缓存它,然后再次计时。
>>> %%timeit
out = [];append=out.append
for x in range(10**6):
append(x**2)
...
1 loops, best of 3: 467 ms per loop
除了列表理解不再泄漏变量的事实之外,另一个区别是类似的东西不再有效:
>>> [x**2 for x in 1, 2, 3] # Python 2
[1, 4, 9]
>>> [x**2 for x in 1, 2, 3] # Python 3
File "<ipython-input-69-bea9540dd1d6>", line 1
[x**2 for x in 1, 2, 3]
^
SyntaxError: invalid syntax
>>> [x**2 for x in (1, 2, 3)] # Add parenthesis
[1, 4, 9]
>>> for x in 1, 2, 3: # Python 3: For normal loops it still works
print(x**2)
...
1
4
9
在CoffeeScript中,我们还可以在数组中存储一组对象。 list推导用于将对象数组映射到另一个数组。 语法 (Syntax) 假设我们在CoffeeScript中有一个对象数组,如[{key1: "value", key2: value}, {key1: "value", key2: value}]那么你可以使用list [{key1: "value", key2: value}, {ke
Python3 列表 描述 list() 方法用于将元组转换为列表。 注:元组与列表是非常类似的,区别在于元组的元素值不能修改,元组是放在括号中,列表是放于方括号中。 语法 list()方法语法: list( seq ) 参数 list -- 要转换为列表的元组。 返回值 返回列表。 实例 以下实例展示了 list()函数的使用方法: #!/usr/bin/python3 aTuple =
主要内容:初始化列表,在列表中插入元素,从列表中删除元素,遍历列表——访问列表的每一个元素列表是一种非连续的存储容器,由多个节点组成,节点通过一些变量记录彼此之间的关系,列表有多种实现方法,如单链表、双链表等。 列表的原理可以这样理解:假设 A、B、C 三个人都有电话号码,如果 A 把号码告诉给 B,B 把号码告诉给 C,这个过程就建立了一个单链表结构,如下图所示。 图:三人单向通知电话号码形成单链表结构 如果在这个基础上,再从 C 开始将自己的号码告诉给自己所知道号码的主人,这样就形
本文向大家介绍Java8语法糖之Lambda表达式的深入讲解,包括了Java8语法糖之Lambda表达式的深入讲解的使用技巧和注意事项,需要的朋友参考一下 一、Lambda表达式简介 Lambda表达式,是Java8的一个新特性,也是Java8中最值得学习的新特性之一。(另一个新特性是流式编程。) Lambda表达式,从本质上讲是一个匿名方法。可以使用这个匿名方法,实现接口中的方法。 功能:通常使
本文向大家介绍C# using语法糖图文详解,包括了C# using语法糖图文详解的使用技巧和注意事项,需要的朋友参考一下 前言 什么是语法糖? (语法糖就是像糖一样的语法…) 语法糖(Syntactic sugar),又名糖衣语法,最早是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的。 通俗点来讲就是简化后的语法,但是其效果和原先语法是一样的,只是更方便我们程序员使用
本文向大家介绍详解es6超好用的语法糖Decorator,包括了详解es6超好用的语法糖Decorator的使用技巧和注意事项,需要的朋友参考一下 Decorator(修饰器/装饰器)是es6提出的语法糖,用于修改类的行为。不过目前主流浏览器都没有很好的支持,我们需要用babel来转换为浏览器能识别的语言。在这篇文章中将介绍decorator的基础用法和一些应用实例。 1.修饰类 (1) 基础用法