2013-10-15 37 views
3

Python的AST定義了何時有ast.BoolOp超過兩個值?

BoolOp(boolop op, expr* values) 

我本來期望它是類似於BinOp,具有leftright值布爾表達式。

有人可以給我一個示例代碼,其中AST會有一些不同於2的值嗎?

編輯:

顯然x and y and z導致三個值。因此,讓我改述一下:

爲什麼這不是建模爲兩個嵌套的BoolOp表達式?

+0

布爾運算符必須是特殊情況,因爲快捷方式;當評估「A和B和C」時,如果「A」爲「False」,則「B」和「C」不會評估。 –

+3

當然,它們的評估方式與BinOp不同。但是'A和B和C'可以被看作'A和(B和C)'而不會改變它。 – Stefan

回答

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   
+1

我認爲OP得到了這個,並問*爲什麼*,因爲這使得'BoolOp'與'BinOp'不同(因此可能違反了簡單規則)。 –

+0

「a和b和c」與「a和(b和c)」有什麼不同? – Stefan

+1

@Lawnmower:無論如何。這可能是一個優化,給我一個'grep' CPython源代碼。 –