【问题标题】:Why is '1 + lambda: 1' a SyntaxError but '1 + (lambda: 1)' a TypeError?为什么 '1 + lambda: 1' 是 SyntaxError 而 '1 + (lambda: 1)' 是 TypeError?
【发布时间】:2016-01-03 16:15:31
【问题描述】:

在交互式解释器中,以下两个表达式会根据添加的括号引发不同的错误:

1 + lambda: 1 导致SyntaxError

>>> 1 + lambda: 1
  File "<ipython-input-17-ae284d908963>", line 1
     1 + lambda: 1
              ^
SyntaxError: invalid syntax

1 + (lambda: 1) 导致TypeError

>>>> 1 + (lambda: 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'function'

我理解SyntaxErrorTypeError 的区别,即它们的本质含义,但我不太明白为什么会发生这种情况。

我试过reading the Grammar,但它对我来说真的是希腊语。 expr(虽然我会表示表达式)定义为:

expr: xor_expr ('|' xor_expr)*

而 lambda:

lambdef: 'lambda' [varargslist] ':' test

这些并没有太大帮助。这同样适用于 Python 2.x 和 3.x。那么,为什么括号会在这种情况下改变异常结果呢?

【问题讨论】:

    标签: python python-2.7 python-3.x syntax


    【解决方案1】:

    为什么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
    

    [注意:从testor_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 会发现 intfunction 的对象不支持添加。当它发现它时,会引发 TypeError

    >>> exec(code_obj)
    # TypeError: unsupported operand type(s) for +: 'int' and 'function'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-04
      • 1970-01-01
      • 1970-01-01
      • 2012-03-28
      • 2020-06-26
      • 2018-09-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多