I have operation where short circuit evaluation leads to very unpredictable results, that don’t produce exceptions:
The original implementation compares generator values and is very complex so I will omit it for now, but keep in mind that the __and__
method plays a crucial role and I need to be certain if is executed or not.
This code is an illustrative example of the kind short-circuit i meant:
class MyClass:
def __init__(self, a ):
self.value = a
def __le__(self, other):
print("le")
if isinstance(other, MyClass):
return MyClass(self.value <= other.value)
return MyClass(self.value <= other)
def __ge__(self, other):
print("ge")
if isinstance(other, MyClass):
return MyClass(self.value >= other.value)
return MyClass(self.value >= other)
def __and__(self, other):
print("NOT IMPLEMENTED")
return 4
def __rand__(self, other):
print("NOT IMPLEMENTED")
return 4
def __str__(self):
return str(self.value)
# Example usage
a = 1
b = MyClass(2)
c = 3
print(a <= b <= c) # __and__ not and called, hm...
print()
print((a <= b) and (b <= c)) # __and__ not being called, bad
print()
print((a <= b) & (b <= c)) # __and__ is called, everything is fine
print()
print(type((a <= b)))
print(type((b <= c)))
As you can see __and__
is only called if is called with “&” that prevents the short circuit, but in the real use case is hard to know when __and__
is being skipped, and from a maintainability perspective it would be wise to raise an error, otherwise I may end up having short circuited structures giving wrong results.
Looking at numpy:
a<b<c of three arrays fails with an exception while (a<b) & (b<c) works just fine. In my case (a<b) & (b<c) works fine but a<b<c works as well, without an exception but with wrong values.
My question is if there a way to prevent or at least detect short circuit of a class? solely relying in not writing anything that can be short-circuited is hard to maintain and catch.
It seems to me that the exception raised in numpy for this caise is accidental but convenient, i need to have at least something similar, just imagine the mess that would have numpy if (a<b) and (b<c) would return something arbitrary.