On NumPy 1.13+, you can do this with NumPy-specific hooks, but you can't have your __rsub__
beat __sub__
methods in general.
__rsub__
is tried if the left operand's __sub__
can't handle the operation, but the left operand can handle this operation. A NumPy array's __sub__
will accept any RHS and perform a broadcasted subtraction. Your object's __rsub__
only comes into play for the individual operations in the broadcasted subtraction.
There is one very limited case where __rsub__
is tried first, which is if the class of the RHS is a subclass of the class of the LHS. You could technically subclass numpy.ndarray
, but that would come with a lot of extra baggage and still do nothing for numpy.matrix([[1]]) - obj
or other subclasses.
There is no way to say "I want my __rsub__
to win over everything". It doesn't exist, and it wouldn't make sense for it to exist, because what would happen if you tried to subtract two objects that both want to declare their method beats everything?
So that's the general case. Specifically for NumPy, though, you can hook into the mechanisms that numpy.ndarray.__sub__
delegates to.
NumPy arrays delegate __sub__
to the NumPy ufunc machinery. There are a bunch of weird customization options there, but we're interested in a specific use of one specific option: by setting __array_ufunc__
to None
at class level, you can declare a class incompatible with ufuncs. This means that all NumPy operator overloads will return NotImplemented
, letting your class handle the operation. This affects all operators and a bunch more stuff, but in a way that you probably want:
class MyClass:
__array_ufunc__ = None
def __rsub__(self, other):
print(type(other), other)
If you want something more targeted than blocking all ufuncs, you can implement an actual __array_ufunc__
method and just handle the case where the ufunc is subtraction and an instance of your class is the RHS:
class MyClass:
def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
if ufunc is not numpy.subtract:
return NotImplemented
if method != '__call__':
return NotImplemented
if len(inputs) != 2 or inputs[1] is not self:
return NotImplemented
if kwargs:
return NotImplemented
return self.__rsub__(inputs[0])
def __rsub__(self, other):
print(type(other), other)