I have a little helper class:
class AnyOf(object): def __init__(self, *args): self.elements = args def __eq__(self, other): return other in self.elements
This lets me do sweet magic like:
>>> arr = np.array([1,2,3,4,5]) >>> arr == AnyOf(2,3) np.array([False, True, True, False, False])
without having to use a list comprehension (as in np.array(x in (2,3) for x in arr
).
(I maintain a UI that lets (trusted) users type in arbitrary code, and a == AnyOf(1,2,3)
is a lot more palatable than a list comprehension to the non-technically savvy user.)
However!
This only works one way! For example, if I were to do AnyOf(2,3) == arr
then my AnyOf
class’s __eq__
method never gets called: instead, the NumPy array’s __eq__
method gets called, which internally (I would presume) calls the __eq__
method of all its elements.
This lead me to wonder: why does Python not allow a right-sided equivalent to __eq__
? (Roughly equivalent to methods like __radd__
, __rmul__
, et cetera.)
Advertisement
Answer
An __req__
may have been considered more confusing than useful in the language. Consider if class Left
defines __eq__
and class Right
defines __req__
, then Python is obliged to make a consistent decision about who gets called first in Left() == Right()
(and we would presumably like the result to be equivalent, either way). They can’t both win.
However, the Python datamodel does allow a way for you to do what you want here. From either side you can control this comparison, but you’ll need to define AnyOf
in a particular way. If you want AnyOf
to control the eq from the right hand side, you may define it to be a subclass of np.ndarray
.
if I were to do
AnyOf(2,3) == arr
then myAnyOf
class’s__eq__
method never gets called
Actually, no, there’s a fundamental misunderstanding evident here. The left hand side always gets first try at the equality comparison, unless the right hand side is a subclass of the type of the left hand side.
arr == AnyOf(2,3)
In the comparison shown above, your custom __eq__
is being called, because the numpy array calls it! So np.ndarray
wins, and it decides to check once per element. It literally could do anything else, including not calling your AnyOf.__eq__
at all.
AnyOf(2,3) == arr
In the comparison shown above, your class does get the first try at the comparison, and it fails because of the way in
was used – return other in self.elements
is checking if an array is in a tuple.