What is the operator precedence when writing a double inequality in Python (explicitly in the code, and how can this be overridden for arrays?)

天涯浪子 提交于 2019-12-05 01:38:33

I'm not totally sure what you're looking for, but a quick disassembly shows that a < b < c is not compiled to the same bytecode as a < b and b < c

>>> import dis
>>>
>>> def f(a, b, c):
...     return a < b < c
...
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 DUP_TOP
              7 ROT_THREE
              8 COMPARE_OP               0 (<)
             11 JUMP_IF_FALSE_OR_POP    21
             14 LOAD_FAST                2 (c)
             17 COMPARE_OP               0 (<)
             20 RETURN_VALUE
        >>   21 ROT_TWO
             22 POP_TOP
             23 RETURN_VALUE
>>>
>>> def f(a, b, c):
...     return a < b and b < c
...
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (a)
              3 LOAD_FAST                1 (b)
              6 COMPARE_OP               0 (<)
              9 JUMP_IF_FALSE_OR_POP    21
             12 LOAD_FAST                1 (b)
             15 LOAD_FAST                2 (c)
             18 COMPARE_OP               0 (<)
        >>   21 RETURN_VALUE

Edit 1: Digging further, I think this is something weird or wrong with numpy. Consider this example code, I think it works as you would expect.

class Object(object):
    def __init__(self, values):
        self.values = values
    def __lt__(self, other):
        return [x < other for x in self.values]
    def __gt__(self, other):
        return [x > other for x in self.values]

x = Object([1, 2, 3])
print x < 5 # [True, True, True]
print x > 5 # [False, False, False]
print 0 < x < 5 # [True, True, True]

Edit 2: Actually this doesn't work "properly"...

print 1 < x # [False, True, True]
print x < 3 # [True, True, False]
print 1 < x < 3 # [True, True, False]

I think it's comparing boolean values to numbers in the second comparison of 1 < x < 3.

Edit 3: I don't like the idea of returning non-boolean values from the gt, lt, gte, lte special methods, but it's actually not restricted according to the Python documentation.

http://docs.python.org/reference/datamodel.html#object.lt

By convention, False and True are returned for a successful comparison. However, these methods can return any value...

Óscar López

Both have the same precedence, but are evaluated from left-to-right according to the documentation. An expression of the form a <= b <= c gets expanded to a <= b and b <= c.

but the real question is how this gets implemented in code.

Do you mean how the interpreter transforms it, or what? You already said

a (logical operator) b (logical operator) c 
    --> (a logical operator b) and (b logical operator c)

so I'm not sure what you're asking here OK, I figured it out: no, you cannot override the expansion from a < b < c into (a < b) and (b < c) IIUC.


I'm curious so that I can replicate this kind of __lt__ and __gt__ behavior in some of my own classes, but I am confused about how this is accomplished holding the middle argument constant.

It depends which of a, b and c in the expression a < b < c are instances of your own class. Implementing your __lt__ and __gt__ and methods gets some of the way, but the documentation points out that:

There are no swapped-argument versions of these methods (to be used when the left argument does not support the operation but the right argument does)

So, if you want Int < MyClass < Int, you're out of luck. You need, at a minimum, MyClass < MyClass < Something (so an instance of your class is on the LHS of each comparison in the expanded expression).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!