2016-11-28 35 views
3

你能解释一下链式比较的语法分析树是什么样子的吗?三种操作数比较如何在Python下工作?

据我所知,在大多数语言中,它构造了基于操作符关联的节点,所以在a < b < c中将会有一个布尔值作为左侧或右侧操作数。

但是在Python中这样的表达式几乎等于a < b and b < cb只能评估一次)。

什么是这种转换的生成语法规则?基本上,在这种情况下,Python解释器是如何构造分析树的?

+0

的语法规则是简单地'比较:EXPR(comp_op表达式)*'。 –

+0

“这样的表达几乎相当于'a

+0

@ PM2Ring是的,这就是为什么我写了“几乎”他们是相等的,如果没有计算副作用b –

回答

6

comparison grammar是不是很有趣在这里,它只是让你添加多个比较器来操作:

comparison ::= or_expr (comp_operator or_expr)* 
comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!=" 
        | "is" ["not"] | ["not"] "in" 

所以,让我们直接问了Python语法分析器,通过使用ast module(简单地询问了Python编译器本身只返回抽象语法树):

>>> import ast 
>>> ast.dump(ast.parse('a > b > c', mode='eval')) 
"Expression(body=Compare(left=Name(id='a', ctx=Load()), ops=[Gt(), Gt()], comparators=[Name(id='b', ctx=Load()), Name(id='c', ctx=Load())]))" 

所以存在的仅仅是Compare节点,多个运营商和比较S:

Compare(
    left=Name(id='a'), 
    ops=[Gt(), Gt()], 
    comparators=[Name(id='b'), Name(id='c')]) 

(I省略Expressionctx份)。

这可以让解释器根据需要评估比较器(例如,如果a < b为假,则不必考虑其余比较器)。

所得字节码使用条件跳转跳过其余比较:

>>> import dis 
>>> dis.dis(compile('a > b > c', '', 'eval')) 
    1   0 LOAD_NAME    0 (a) 
       2 LOAD_NAME    1 (b) 
       4 DUP_TOP 
       6 ROT_THREE 
       8 COMPARE_OP    4 (>) 
      10 JUMP_IF_FALSE_OR_POP 18 
      12 LOAD_NAME    2 (c) 
      14 COMPARE_OP    4 (>) 
      16 RETURN_VALUE 
     >> 18 ROT_TWO 
      20 POP_TOP 
      22 RETURN_VALUE