我正在使用Python 2.7。
这就是发生的事情:
>>> 2+++2
4
我不确定python解释器如何解释这个表达式。
我能想到的唯一原因是第一个“+”之后的连续“+”被认为是一元运算符而第一个“+”被认为是二元运算符,但实际上正在发生的机制是什么我不确定。
我希望有人能够根据Python编程语言的语法细节来回答这个问题,并报告其他一些含糊不清的表达方式。我想出了下面列出的一些其他表达式(结果):
>>> 2------------2
4
>>> 2+-2+-2+-2+-2+-2-------------------------2
-10
答案 0 :(得分:7)
你是对的;正如您所料,Python将其解释为2 + (++2)
。你可以通过查看2 + 2和2 +++ 2的编译字节码来看到这一点,如下所示:
>>> dis.dis(lambda: 2+2)
1 0 LOAD_CONST 2 (4)
3 RETURN_VALUE
>>> dis.dis(lambda: 2+++2)
1 0 LOAD_CONST 1 (2)
3 LOAD_CONST 1 (2)
6 UNARY_POSITIVE
7 UNARY_POSITIVE
8 BINARY_ADD
9 RETURN_VALUE
您可能想知道为什么Python会像这样解析2 +++ 2。首先,代码被分解为令牌:
>>> from cStringIO import StringIO
>>> import tokenize
>>> tokenize.generate_tokens(StringIO("2+++2").readline)
9 <generator object generate_tokens at 0x0000000007BC7480>
>>> list(tokenize.generate_tokens(StringIO("2+++2").readline))
10
[(2, '2', (1, 0), (1, 1), '2+++2'),
(51, '+', (1, 1), (1, 2), '2+++2'),
(51, '+', (1, 2), (1, 3), '2+++2'),
(51, '+', (1, 3), (1, 4), '2+++2'),
(2, '2', (1, 4), (1, 5), '2+++2'),
(0, '', (2, 0), (2, 0), '')]
然后解析器将令牌列表关联到语法树中:
>>> st = ast.parse("2+++2")
>>> st
36 <_ast.Module at 0x7d2acc0>
>>> ast.dump(st)
37 'Module(body=[Expr(value=BinOp(left=Num(n=2), op=Add(), right=UnaryOp(op=UAdd(), operand=UnaryOp(op=UAdd(), operand=Num(n=2)))))])'
这符合标准的消歧规则。
答案 1 :(得分:2)
看看Python定义unary和binary算术运算的方式。特别是一元的表达方式:
u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr
你可以看到"+" u_expr
部分,这几乎意味着一个数字+
后跟一个数字是一个有效的一元表达式(有点递归,是吗?)。
另一方面,你得到了这两个:
m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr
| m_expr "%" u_expr
a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr
这几乎意味着,当你有一个二进制表达式时,你读取第一个原子,然后读取符号,并读取下一个二进制/一元表达式。阅读代码如下:
2+-2+-2+-2+-2+---2+-2
基本上就像:
2 + (-2) + (-2) + (-2) + (-2) + (-(-(-2))) + (-2)
答案 2 :(得分:1)
在grammar:
中完全清楚arith_expr: term (('+'|'-') term)*
term: factor (('*'|'/'|'%'|'//') factor)*
factor: ('+'|'-'|'~') factor | power
因此,由于任何因子都可以在一个一元运算符之前,这将延伸到算术表达式消耗二元运算符。它根本不含糊,因为我们既没有C ++运算符也没有Haskell定义新运算符的能力。