看两个列表推导,每个包含两个用于子句。我们看到如果for子句的顺序正确,Python就会感到困惑。但如果它们是错误的方式,Python可以处理它。为什么呢?
Python 3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> [x + y for x in range(y) for y in range(4)]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
>>> [x + y for y in range(4) for x in range(y)]
[1, 2, 3, 3, 4, 5]
>>>
答案 0 :(得分:5)
在
[x + y for x in range(y) for y in range(4)]
y
中的range(y)
在该地方未知。相当于:
for x in range(y):
for y in range(4):
# x + y
有关详细信息,请参阅PEP-0202:
- The form [... for x... for y...] nests, with the last index
varying fastest, just like nested for loops.
答案 1 :(得分:3)
这是一个很好的问题!
答案是,与大多数Python不同,这些嵌套的理解是按照解释器想要的方式编写的,而不是你想要的方式。
口译员从右到左阅读理解:
[(this is interpreted last) for (this is interpreted first)]
但是,每个子句都是从左到右阅读的,因此在y in range(4) for x in range(y)
中,您必须先解释y
之前的内容,然后才能range(y)
。
这令人困惑,因为当你想到嵌套理解时,你会从右到左思考。
答案 2 :(得分:3)
列表推导首先被引入Python作为这种形式的语法糖:
L = []
for innerseq in seq:
for item in innerseq:
LOOPS
if CONDITION:
L.append(BODY)
这转变为:
[BODY for innerseq in seq for item in innerseq LOOPS if CONDITION]
为了使转换更加明显,请注意for
表达式和if
条件的顺序与正常for
- 循环中的顺序完全相同。这就是列表推导使用相同顺序的原因。
当你将循环重写为理解时,唯一改变的是循环体的位置(它移动到前面,你通常会初始化空容器)。关于循环的其他所有内容都保持完全相同。
你喜欢的替代品(你的“正确方式”)似乎远更令人困惑。我们只是颠倒循环的顺序,或者我们颠倒理解中每个子句的顺序。即,或者:
[BODY LOOPS[::-1] for item in innerseq for innerseq in seq if CONDITION]
或
[BODY if CONDITION LOOPS[::-1] for item in innerseq for innerseq in seq]
其中任何一个看起来都是不必要的复杂变换。
另请注意,其他语言在列表推导中使用相同的循环顺序。这是一些Clojure:
user=> ; using your suggested "right" order
user=> (for [x (range y) y (range 4)] (+ x y))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: y in this context, compiling:(NO_SOURCE_PATH:1)
user=> ; you need to use the same "wrong" order as Python
user=> (for [y (range 4) x (range y)] (+ x y))
(1 2 3 3 4 5)
这与Python相同,尽管Clojure最后将理解的“主体”放在了一起。
如果有帮助,可以想象for
循环的排列方式与汽车里程表中的数字相同。最右边的循环旋转速度最快。