什么时候有ast.BoolOp超过两个值?

时间:2013-10-15 09:42:34

标签: python python-2.7

Python的AST使用

定义布尔表达式
BoolOp(boolop op, expr* values)

我原以为它与BinOp类似,leftright值。

有人可以给我一个示例代码,其中AST会有两个不同的值吗?

编辑:

显然x and y and z会产生三个值。所以让我改写一下:

为什么这不是两个嵌套的BoolOp表达式?

1 个答案:

答案 0 :(得分:4)

a and b and c被Python解析器视为三元连接:

>>> e = ast.parse('''a and b and c''').body[0].value
>>> e.op
<_ast.And object at 0x254d1d0>
>>> e.values
[<_ast.Name object at 0x2d9ba50>, <_ast.Name object at 0x2d9ba90>, <_ast.Name object at 0x2d9bad0>]

虽然括号将强制它作为递归二元连接进行解析:

>>> ast.parse('''a and (b and c)''').body[0].value.values
[<_ast.Name object at 0x2d9b990>, <_ast.BoolOp object at 0x2d9bb10>]

我不确定为什么会这样。在任何情况下,根据CPython源代码中的单元测试,BoolOp可能不会少于两个子节点。

我最初认为这将是一种优化,但a and b and c完全等同于a and (b and c);他们甚至生成相同的字节码:

>>> def f(a, b, c):
...     return a and b and c
... 
>>> def g(a, b, c):
...     return a and (b and c)
... 
>>> from dis import dis
>>> dis(f)
  2           0 LOAD_FAST                0 (a)
              3 JUMP_IF_FALSE_OR_POP    15
              6 LOAD_FAST                1 (b)
              9 JUMP_IF_FALSE_OR_POP    15
             12 LOAD_FAST                2 (c)
        >>   15 RETURN_VALUE        
>>> dis(g)
  2           0 LOAD_FAST                0 (a)
              3 JUMP_IF_FALSE_OR_POP    15
              6 LOAD_FAST                1 (b)
              9 JUMP_IF_FALSE_OR_POP    15
             12 LOAD_FAST                2 (c)
        >>   15 RETURN_VALUE