If we have the setup:
class TupleVector(tuple):
def __eq__(self, other: object) -> bool:
print("TupleVector.__eq__")
return super().__eq__(other)
class ListVector(list):
...
Then:
values = (1,)
print(f"== comparison: {ListVector(values) == TupleVector(values)}")
Outputs:
TupleVector.__eq__
== comparison: False
Showing that the __eq__
call has been reflected to call the right-hand side TupleVector.__eq__()
.
The reason can be seen if we directly call ListVertorListVector.__eq__()
:
print(f"__eq__ comparison: {ListVector(values).__eq__(TupleVector(values))}")
Which outputs:
__eq__ comparison: NotImplemented
The Python documentation states:
NotImplemented
A special value which should be returned by the binary special methods (e.g.
__eq__()
,__lt__()
,__add__()
,__rsub__()
, etc.) to indicate that the operation is not implemented with respect to the other type; may be returned by the in-place binary special methods (e.g.__imul__()
,__iand__()
, etc.) for the same purpose. It should not be evaluated in a boolean context.NotImplemented
is the sole instance of thetypes.NotImplementedType
type.Note: When a binary (or in-place) method returns
NotImplemented
the interpreter will try the reflected operation on the other type (or some other fallback, depending on the operator). If all attempts returnNotImplemented
, the interpreter will raise an appropriate exception. Incorrectly returningNotImplemented
will result in a misleading error message or theNotImplemented
value being returned to Python code. See Implementing the arithmetic operations for examples.
Since listVector.__eq__(other)
is not implemented then it goes up the class hierarchy and calls list.__eq__()
which returns the NotImplemented
object and this causes Python to try to evaluate the reflected operation other.__eq__(listVector)
, which is implemented and returns a boolean.