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

Comparison operators can be encoded in python, so, for example, x < y < z should give the result (x < y) and (y < z) , except that y guaranteed to be evaluated only once.

The abstract syntax tree of this operation looks like this:

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

Printed Version:

 Module Expr Compare Num Lt Lt Num Num 

But he seems to be analyzing something like 0 < < 1 2 , and I'm not sure how to put up with the logical result of something like 0 < 1 and 1 < 2 .

How to explain ast's explanation for chain comparisons?

+8
python abstract-syntax-tree
source share
3 answers

The rationale for this is really mentioned in ast docs

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

If it has been rated as two separate comparisons, for example

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

Then he actually compares the logical result of the first comparison with the integer in the second comparison.

Something like this will not work

 -5 < -4 < -3 

Since it will be rated as

 (-5 < -4) < -3 

What is rated as

 1 < -3 

Therefore, instead, it was considered as one expression. The python implementation of the Compare operation will look something like this:

 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 
+5
source share

I think you need to think of it as a short circuit of what needs to be done. for example if you zip ops with comparators and then work with them one at a time:

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

Obviously, I leave a bunch of imagination here ... for example. I did not define evaluate . However, it is rather difficult to determine, since we do not know what the expression of the comparator looks like in the general case.

+3
source share

I would like to add Brendan Abel's answer with my version of the Compare() function, which IMHO is a little easier to understand:

 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 
+2
source share

All Articles