如何解释链式比较操作的抽象语法树?

How to explain the abstract syntax tree of chained comparison operations?

比较运算符可以在 python 中链接,因此例如 x < y < z 应该给出 (x < y) and (y < z) 的结果,除了 y 保证只被评估一次。

这个操作的抽象语法树是这样的:

>>> ast.dump(ast.parse('0 < 1 < 2'), annotate_fields=0)
'Module([Expr(Compare(Num(0), [Lt(), Lt()], [Num(1), Num(2)]))])'

印刷精美:

Module
  Expr
    Compare
      Num
      Lt
      Lt
      Num
      Num

但它似乎被解析为 0 < < 1 2 之类的东西,我不确定如何将其与 0 < 1 and 1 < 2 之类的逻辑结果相协调。

如何解释链式比较的 ast?

我认为您需要将其视为待办事项的短路管道。例如如果你 zip opscomparators,然后一次处理一个:

result = left
for op, comparator in zip(ops, comparators):
    result = result and evaluate(result, op, comparator)
    if not result:
        break

显然,我在这里留下了很多想象......例如我没有定义 evaluate。然而,这是一件很难定义的事情,因为我们不知道一般情况下比较器表达式是什么样的。

这背后的原因实际上在 ast 文档中提到

-- need sequences for compare to distinguish between
-- x < 4 < 3 and (x < 4) < 3
| Compare(expr left, cmpop* ops, expr* comparators)

如果它被评估为两个单独的比较,就像这样

Module(Expr(Compare(Compare(Num(0), [Lt()], [Num(1)]), [Lt()], [Num(2)]))])

那么其实就是把第一次比较的布尔值结果和第二次比较的整数进行比较。

这样的东西是行不通的

-5 < -4 < -3

因为它会被评估为

(-5 < -4) < -3

评估为

1 < -3

因此,它被作为单个表达式处理。 python Compare 操作的实现看起来像这样

def Compare(left, ops, comparators):
    if not ops[0](left, comparators[0]):
        return False

    for i, comparator in enumerate(comparators[1:], start=1):
        if not ops[i](comparators[i-1], comparator):
            return False
    return True

我想用我的 Compare() 函数版本来补充 ,恕我直言,它更容易理解:

def Compare(left, ops, comparators):
    for x, op, y in zip([left] + comparators[:-1], ops, comparators):
        if not op(x, y):
            return False
    return True