我正在编写一个解析器,在调试过程中,我发现显然这是合法的Python:
for [] in [[]]: print 0
这是(!):
for [][:] in [[]]: print 0
我不会责怪解析器感到困惑...... 我无法弄清楚如何解释它!
这句话究竟是什么意思?
答案 0 :(得分:14)
在执行方面:没有。
for
循环本身循环遍历一个空列表,因此不会发生迭代。
这是件好事,因为for []
意味着:将循环中的每个条目分配给0个变量。后一部分可能让你感到困惑。
该语句是合法的,因为target token token_list
允许您将序列中的值分配给同样大的变量名序列;我们把这个元组称为拆包。以下是目标列表在分配和删除方面更有用的示例:
(a, b, c) = range(3)
del a, b, c
您可以在for
循环中执行相同操作:
nested = [[1,2,3], [4,5,6]]
for a, b, c in nested:
print nested
您可以同时使用target_list
令牌的元组和列表,这也是合法的:
[a, b] = (1, 2)
但是,在Python中,列表可以为空。因此,以下是合法的,无论多么不合情理:
[] = []
最后,这也是:
nested_empty = [[], [], []]
for [] in nested_empty:
pass
目标列表更有趣:
[][:] = [1, 2, 3]
现在左侧正在分配中使用切片。来自文档:
如果目标是切片:评估参考中的主表达式。它应该产生一个可变序列对象(例如列表)。分配的对象应该是相同类型的序列对象。接下来,评估下限和上限表达式,只要它们存在;默认值为零和序列的长度。边界应该评估为(小)整数。如果任一边界为负数,则将序列的长度添加到其中。生成的边界被裁剪为介于零和序列的长度之间(包括端点)。最后,要求序列对象用指定序列的项替换切片。切片的长度可能与指定序列的长度不同,因此如果对象允许,则改变目标序列的长度。
所以这里我们不再使用元组拆包了;相反,我们用右侧列表替换左侧列表的一部分。但是因为在我们的例子中,左侧列表是一个匿名列表文字,结果修改后的列表会再次丢失。
但是因为这样的赋值在for循环中也是合法的,所以下面是合法的语法,尽管是非语言的:
for [][:] in [range(i) for i in range(10)]: print 0
答案 1 :(得分:1)
for [] in [[]]: print 0
相当于:
In [44]: for [x,y] in [[1,2],[3,4],[5,6]]: # or even (x,y) will work
print x,y
....:
....:
1 2
3 4
5 6
但前一个人希望没有从列表中返回值,即列表中的值为空或len()
为0
。< / p>
您无法使用()
,因为它无效。
因为在python中,你可以像这样分配:
In [56]: x,y=[1,2] #this means that the expression on RHS should return two values
# (x,y)=[1,2] or x,y=(1,2) or (x,y)=(1,2) all are valid
In [57]: x
Out[57]: 1
In [58]: y
Out[58]: 2
In [62]: x,y='ab' #assign a to x and b to y
In [63]: x
Out[63]: 'a'
In [64]: y
Out[64]: 'b'
答案 2 :(得分:1)
这是我最好的猜测:
for [] in [[]]
表示“对于此列表[]
中的[[]]
(空列表对象)的每个实例(一个列表只包含一个元素,这是一个空列表对象),{ {1}}。
在第二种情况下,我认为print 0
只会使用所有默认值调用[:]
,这将只占整个列表的一部分。在内部可能会做某事,例如制作列表对象的副本,但在这种情况下的效果应该是相同的。
答案 3 :(得分:1)
for..in结构在Python手册中描述
http://docs.python.org/reference/compound_stmts.html#the-for-statement
in
关键字
for [i,j] in [(1,2),(3,4),(5,6)]:
print i, j
for [i,j] in [[1,2],[3,4],[5,6]]:
print i, j
手册说它被解释为
i,j = (1,2)
进行第一次迭代,依此类推。因此,您可以拥有一个空的变量列表,因为迭代列表只有一个空列表作为元素。此循环将打印0次。
您正在阅读的解析器是否已自动生成?这种陈述可以由非人类来源产生。我没有看到它的目的。
答案 4 :(得分:1)
for [] in [[]]: print 0
表示对于[[]]中的每个空迭代,即包含空列表的列表,打印0.它不仅限于列表,而且每个迭代都可以放入其中。例如,您可以尝试:
# empty list, empty tuple, empty string, empty unicode
for [] in [[], (), '', unicode()]: print 0
它将打印0次。
[] [:]与[]相同。它将返回一个空列表,所以我的答案与上面的相同。
答案 5 :(得分:0)
假设您有一个如下所示的元组列表:
L = [(1,2), (3,4), (5,6)]
假设您想以某种特殊方式打印这些元组:
for tup in L:
a = tup[0]
b = tup[1]
if a<b:
print a,b
else:
print b,a
但明确指定a
和b
作为tup
的内容是相当繁琐的。所以你可以这样做:
for tup in L:
a,b = tup
if a<b:
print a,b
else:
print b,a
但你可以让它变得更加乏味:
for (a,b) in L: # you could also do "for [a,b] in L"
if a<b:
print a,b
else:
print b,a
这里,(a,b)
模式与迭代返回的元素匹配。在for循环的第一次执行中,迭代返回的元素是(1,2)
,它与(a,b)
进行模式匹配,因此将1
分配给a
和{{ 1}}到2
现在,在第一个示例中,您将迭代包含空列表的列表。这意味着您要尝试打印与此列表中b
一样多的0
s。但它比这更复杂:
当你尝试在我的第三个例子中模式匹配时,python迭代变量的列表(或元组)和迭代器返回的元素,同时分配值。因此,当您的模式不包含变量时,您尝试模式匹配的元素也应为空(并且可迭代)。这解释了以下行为:
[]
......也是这种行为:
>>> for i in 5: print i
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
>>> for [] in [[], 5]: print 0
...
0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
现在,至于你的第二个例子,>>> x,y = (2,5,3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
>>> for [] in [[], [5]]: print 0
...
0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
操作基本上创建了一个被调用列表的副本,因此改变原始列表不会改变副本,反之亦然:
[:]
因此,当您致电>>> L = [1,2,3]
>>> M = L
>>> M[0] = 'a'
>>> print L[0]
'a'
>>> L = [1,2,3]
>>> M = L[:]
>>> M[0] = 'a'
>>> print L[0]
1
时,您所做的只是制作一个新的空列表,其效果与我对您的第一个示例的解释相同