众所周知,元组不是用括号定义的,而是用逗号定义的。 Quote from documentation:
元组由许多以逗号分隔的值组成
因此:
myVar1 = 'a', 'b', 'c'
type(myVar1)
# Result:
<type 'tuple'>
另一个引人注目的例子是:
myVar2 = ('a')
type(myVar2)
# Result:
<type 'str'>
myVar3 = ('a',)
type(myVar3)
# Result:
<type 'tuple'>
即使是单元素元组也需要逗号,并且总是使用括号来避免混淆。 我的问题是:为什么我们不能在列表推导中省略数组的括号?例如:
myList1 = ['a', 'b']
myList2 = ['c', 'd']
print([(v1,v2) for v1 in myList1 for v2 in myList2])
# Works, result:
[('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd')]
print([v1,v2 for v1 in myList1 for v2 in myList2])
# Does not work, result:
SyntaxError: invalid syntax
不是第二个列表理解只是以下循环的语法糖,这确实有效吗?
myTuples = []
for v1 in myList1:
for v2 in myList2:
myTuple = v1,v2
myTuples.append(myTuple)
print myTuples
# Result:
[('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd')]
答案 0 :(得分:12)
Python的语法是LL(1),这意味着它在解析时只向前看一个符号。
[(v1, v2) for v1 in myList1 for v2 in myList2]
在这里,解析器看到类似的东西。
[ # An opening bracket; must be some kind of list
[( # Okay, so a list containing some value in parentheses
[(v1
[(v1,
[(v1, v2
[(v1, v2)
[(v1, v2) for # Alright, list comprehension
然而,如果没有括号,它必须在早些时候作出决定。
[v1, v2 for v1 in myList1 for v2 in myList2]
[ # List-ish thing
[v1 # List containing a value; alright
[v1, # List containing at least two values
[v1, v2 # Here's the second value
[v1, v2 for # Wait, what?
回溯往往比较慢的解析器,因此LL(1)解析器不会回溯。因此,禁止使用含糊不清的语法。
答案 1 :(得分:2)
当我觉得"because the grammar forbids it"有点过于苛刻时,我提出了理由。
它开始将表达式解析为list / set / tuple,并期待,
,而是遇到for
令牌。
例如:
$ python3.6 test.py
File "test.py", line 1
[a, b for a, b in c]
^
SyntaxError: invalid syntax
标记如下:
$ python3.6 -m tokenize test.py
0,0-0,0: ENCODING 'utf-8'
1,0-1,1: OP '['
1,1-1,2: NAME 'a'
1,2-1,3: OP ','
1,4-1,5: NAME 'b'
1,6-1,9: NAME 'for'
1,10-1,11: NAME 'a'
1,11-1,12: OP ','
1,13-1,14: NAME 'b'
1,15-1,17: NAME 'in'
1,18-1,19: NAME 'c'
1,19-1,20: OP ']'
1,20-1,21: NEWLINE '\n'
2,0-2,0: ENDMARKER ''
答案 2 :(得分:1)
没有引发该限制的解析器问题。与Silvio Mayolo的答案相反,LL(1)解析器本来可以解析无括号语法。在原始列表理解补丁的早期版本中,括号是可选的;他们只是为了使含义更清楚而被强制执行。
早在2000年,Guido van Rossum在response中向担心[x, y for ...]
会导致解析器问题的人报价,
不用担心。格雷格·尤因(Greg Ewing)毫无疑问地在Python 自己的语法,这几乎和解析器一样严格。 (它的 LL(1),等效于具有一个的纯递归下降 前瞻令牌,即无回溯。)
这是格雷格的语法:
atom: ... | '[' [testlist [list_iter]] ']' | ... list_iter: list_for | list_if list_for: 'for' exprlist 'in' testlist [list_iter] list_if: 'if' test [list_iter]
请注意,之前的列表语法为
'[' [testlist] ']'
。让我来 用不同的术语解释它:解析器解析一系列逗号分隔的表达式。先前, 它原以为
']'
是紧随其后的唯一可能的令牌。 更改之后,'for'
是另一个可能的跟随标记。这个 知道如何解析匹配的解析器根本没有问题 括号!如果您不支持
[x, y for ...]
,因为它模棱两可 (对于人类读者,而不是解析器!),我们可以更改语法 像这样:'[' test [',' testlist | list_iter] ']'
(请注意,
|
的绑定少于串联,而[...]
的含义是 可选部分。)
另请参阅线程中的next response,Greg Ewing运行所在的线程
>>> seq = [1,2,3,4,5]
>>> [x, x*2 for x in seq]
[(1, 2), (2, 4), (3, 6), (4, 8), (5, 10)]
在列表理解补丁的早期版本中,效果很好。