0

我正在使用 Python 2.7。

这就是发生的事情:

>>> 2+++2
4

我不确定 python 解释器如何解释这个表达式。

我能想出的唯一原因是第一个“+”之后的连续“+”被认为是一元运算符,第一个“+”被认为是二元运算符,但实际上发生的机制是什么我不是肯定。

我希望有人根据 Python 编程语言的语法细节来回答这个问题,并报告其他一些模棱两可的表达方式。我想出了下面列出的其他一些表达式(及其结果):

>>> 2------------2
4
>>> 2+-2+-2+-2+-2+-2-------------------------2
-10
4

3 回答 3

7

你是对的; 2 + (++2)正如您所料,Python 将其解释为。您可以通过查看 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)))))])'

这遵循标准的消歧规则。

于 2013-03-20T11:15:48.313 回答
2

看看 Python 定义一元二元算术运算的方式。尤其是一元表达式:

u_expr ::=  power | "-" u_expr | "+" u_expr | "~" u_expr

您可以看到 part "+" 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)
于 2013-03-20T11:23:24.393 回答
1

语法上很清楚:

arith_expr: term (('+'|'-') term)*
term: factor (('*'|'/'|'%'|'//') factor)*
factor: ('+'|'-'|'~') factor | power

因此,由于任何因素之前都可能有一个一元运算符,因此这将扩展到算术表达式使用二元运算符。这一点也不含糊,因为我们既没有 C 的 ++ 运算符,也没有 Haskell 定义新运算符的能力。

于 2013-03-20T11:28:36.223 回答