chained comparisons in sqlalchemy

  • Last Update :
  • Techknowledgy :

The reason is that Python actually evaluates something akin to this:

_tmp = Couple.NumOfResults(10 < _tmp and _tmp < 20)

In the original example, one should write this code instead:

results = session.query(Couple).filter(and_(10 < Couple.NumOfResults,
   Couple.NumOfResults < 20)).all()

Suggestion : 2

Last Updated : 17 May, 2022

1._
a < b < c

The most common syntax to do it is as follows:

if a < b and b < c: {
   ...
}

In Python, there is a better way to write this using Comparison operator Chaining. The chaining of operators can be written as follows:

if a < b < c: {
   .....
}
  1. Comparisons yield boolean values: True or False.
  2. Comparisons can be chained arbitrarily. For example:
x < y <= z is equivalent to x < y and y <= z,
  1. except that y is evaluated only once. (but in both cases z is not evaluated at all when x < y is found to be false).
  2. Formally, if a, b, c, …, y, z are expressions and op1, op2, …, opN are comparison operators, then a op1 b op2 c … y opN z is equivalent to a op1 b and b op2 c and … y opN z, except that each expression is evaluated at most once.
  3. Also,
a op1 b op2 c

Suggestion : 3

You can compare multiple items with multiple comparison operators with chain comparison. For example,Where OP represents one of the multiple comparison operations you can use, and the letters represent arbitrary valid expressions.,There is no theoretical limit on how many items and comparison operations you use as long you have proper syntax:,The above returns True if each comparison returns True. However, using convoluted chaining is not a good style. A good chaining will be "directional", not more complicated than

You can compare multiple items with multiple comparison operators with chain comparison. For example

x > y > z

is just a short form of:

x > y and y > z

The general form is

a OP b OP c OP d...

The above returns True if each comparison returns True. However, using convoluted chaining is not a good style. A good chaining will be "directional", not more complicated than

1 > x > -4 > y != 8

Note that the expression exp in a > exp > b will be evaluated only once, whereas in the case of

a > exp and exp > b

Suggestion : 4

Python supports chaining of comparison operators, which means if we wanted to find out if b lies between a and c we can do a < b < c, making code super-intuitive. Python evaluates such expressions like how we do in mathematics. which means a < b < c is evaluated as (a < b) and (b < c). C language on the other hand, evaluates a < b < c as ((a < b) < c).,Python has a plethora of comparison operators like <, >, <=, >=, ==, !=, in, and is. The output of the comparison operator is a boolean value - True or False. Python allows chaining of comparison operators which means, to check if b lies between a and c, we can simply do,how Python evaluates chained comparison operators?,ensure that the evaluated value (output from the first compare) remains on top - so that it becomes the first operand of the next expression

Depending on how we evaluate such expressions, the final evaluated changes. So, in python, if we evaluate -3 < -2 < -1, we get True and if evaluate 3 > 2 == 1 we get False.

>>> -3 < -2 < -1
True
   >>>
   3 > 2 == 1
False

But on the other hand, if we evaluate this very expression in C language the output is False.

#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("%d\n", -3 < -2 < -1);
    printf("%d\n", 3 > 2 == 1);
    return 0;
}

$ gcc test.cpp
$ ./a.out
0
1

Python has a plethora of comparison operators like <, >, <=, >=, ==, !=, in, and is. The output of the comparison operator is a boolean value - True or False. Python allows chaining of comparison operators which means, to check if b lies between a and c, we can simply do

>>> a < b < c

The code that generates instructions for comparison expressions is in file Python/compile.c. The snippet that interests us is the function compiler_compare which can be seen below

static int
compiler_compare(struct compiler * c, expr_ty e) {
   ...
   for (i = 0; i < n; i++) {
      VISIT(c, expr,
         (expr_ty) asdl_seq_GET(e - > v.Compare.comparators, i));
      ADDOP(c, DUP_TOP);
      ADDOP(c, ROT_THREE);
      ADDOP_COMPARE(c, asdl_seq_GET(e - > v.Compare.ops, i));
      ADDOP_JUMP(c, JUMP_IF_FALSE_OR_POP, cleanup);
      NEXT_BLOCK(c);
   }
   ...
   ADDOP(c, ROT_TWO);
   ADDOP(c, POP_TOP);
   ...
}
return 1;
}

To achieve this, all we have to do is comment out 3 lines that do exactly that. Post changes the snippet would look something like this.

static int
compiler_compare(struct compiler * c, expr_ty e) {
   ...
   for (i = 0; i < n; i++) {
      VISIT(c, expr,
         (expr_ty) asdl_seq_GET(e - > v.Compare.comparators, i));

      // ADDOP(c, DUP_TOP);
      // ADDOP(c, ROT_THREE);

      ADDOP_COMPARE(c, asdl_seq_GET(e - > v.Compare.ops, i));

      // ADDOP_JUMP(c, JUMP_IF_FALSE_OR_POP, cleanup);

      NEXT_BLOCK(c);
   }
   ...
   ADDOP(c, ROT_TWO);
   ADDOP(c, POP_TOP);
   ...
}
return 1;
}

Suggestion : 5

11 March 2022 , 3 May 2022 , 5 August 2021 , 7 October 2021

One of the things I enjoy about Python is that some of its features make so much sense that you don't even notice that you are using a feature until someone points out that such code wouldn't work in other languages. One such example is comparison chaining! Look at this snippet of code and tell me if it doesn't look natural:

>>> a = 1 >>>
   b = 2 >>>
   c = 3 >>>
   if a < b < c:
   ...print("Increasing seq.")
   ...
   Increasing seq.

Another example usage is for when you want to make sure that three values are all the same:

>>> a = b = 1 >>>
   c = 2 >>>
   if a == b == c:
   ...print("all same")
   ...
   else:
      ...print("some are diff")
      ...
      some are diff >>>
      c = 1 >>>
      if a == b == c:
   ...print("all same")
   ...
   else:
      ...print("some are diff")
      ...
      all same

Look at this code:

>>> a = c = 1 >>>
   b = 2 >>>
   if a != b != c:
   ...print("a, b, and c all different:", a, b, c)
a, b, and c all different: 1 2 1

This snippet shows that an expression like 1 < f() < 0 can actually evaluate to True when it is unfolded:

>>> l = [-2, 2] >>>
   def f():
   ...global l
   ...l = l[::-1]
   ...
   return l[0] >>>
      if 1 < f() and f() < 0:
   ...print("ehh")
   ...
   ehh

In Python, is, is not, in, and not in are comparison operators, so you can also chain them with the other operators. This creates weird situations like

>>> a = 3 >>>
   l = [3, 5] >>>
   if a in l == True:
   ...print("Yeah :D")
   ...
   else:
      ...print("Hun!?")
      ...
      Hun! ?