Python的AST定義了何時有ast.BoolOp超過兩個值?
BoolOp(boolop op, expr* values)
我本來期望它是類似於BinOp
,具有left
和right
值布爾表達式。
有人可以給我一個示例代碼,其中AST會有一些不同於2的值嗎?
編輯:
顯然x and y and z
導致三個值。因此,讓我改述一下:
爲什麼這不是建模爲兩個嵌套的BoolOp
表達式?
Python的AST定義了何時有ast.BoolOp超過兩個值?
BoolOp(boolop op, expr* values)
我本來期望它是類似於BinOp
,具有left
和right
值布爾表達式。
有人可以給我一個示例代碼,其中AST會有一些不同於2的值嗎?
編輯:
顯然x and y and z
導致三個值。因此,讓我改述一下:
爲什麼這不是建模爲兩個嵌套的BoolOp
表達式?
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
我認爲OP得到了這個,並問*爲什麼*,因爲這使得'BoolOp'與'BinOp'不同(因此可能違反了簡單規則)。 –
「a和b和c」與「a和(b和c)」有什麼不同? – Stefan
@Lawnmower:無論如何。這可能是一個優化,給我一個'grep' CPython源代碼。 –
布爾運算符必須是特殊情況,因爲快捷方式;當評估「A和B和C」時,如果「A」爲「False」,則「B」和「C」不會評估。 –
當然,它們的評估方式與BinOp不同。但是'A和B和C'可以被看作'A和(B和C)'而不會改變它。 – Stefan