为什么1 + lambda: 1 会引发SyntaxError?
由于语法不支持而引发语法错误。从Full Grammar Specification 我们可以看到test 规则,它is the basic expression element 而不是名字不好的expr,具有以下形式:
test: or_test ['if' or_test 'else' test] | lambdef
test_nocond: or_test | lambdef_nocond
在哪里the vertical bar | is used to seperate alternative substitutions for this rule。
因此,每个表达式必须以 or_test 或 lambdadef 开头。如果在表达式的开头找不到lambdadef,则在解析过程中会适当地引发SyntaxError:
>>> import parser; parser.expr('1 + lambda: 1')
# SyntaxError: invalid syntax
[注意:从test 的or_test 成员中,我们几乎可以通过替换生成Python 中的所有其他表达式]
为什么1 + (lambda: 1) 会引发TypeError?
因为括号被用作enclosures:
enclosure ::= parenth_form | list_display | dict_display | set_display
| generator_expression | yield_atom
parenth_form 是:
parenth_form ::= "(" [expression_list] ")"
这里的括号会将lambda: 1 与表达式的其余部分隔离开来,并将其限制在自己的表达式(test) 中。由于新表达式是(lambda: 1),因此它在语法上是有效的(因为lambdadef 是表达式开头的一个元素)。因此,没有可以触发SyntaxError 的规则。 (如果您执行了1 + (1 + lambda: 1),则会触发相同的SyntaxError)。
此外,我们实际上可以通过查看基于列表的解析树的(相关部分)并使用Include/graminit.h 中包含的数字。
我们可以生成解析树:
>>> parse_tree = parser.expr("1 + (lambda: 1)")
>>> parse_tree.tolist()
# further up the list, another [304, exists, denoting the
# 'outer' expression
#.. snipped ..
[323,
[7, '(', 1, 4],
[324,
[304, # <-- indicating new expression
[306,
[1, 'lambda', 1, 5],
[11, ':', 1, 11],
#.. snipped ..
通过查看definition for test,我们可以看到304 定义了一个新的test。
因此,表达式将被解析并因此编译没有问题:
>>> code_obj = parse_tree.compile()
在执行期间进行评估,Python 会发现 int 和 function 的对象不支持添加。当它发现它时,会引发 TypeError:
>>> exec(code_obj)
# TypeError: unsupported operand type(s) for +: 'int' and 'function'