implement __rmul__ from both sides, python

2.5k views Asked by At

I there a way to implement rmul so that it works in both directions? I'm using mul to multiply two vectors a and b of class R3 element by element. Later I want to be able to multiply each element by a number with an operator like 2*a and a*2.

class R3(object):
    def __init__(self,an_array):
        self.a = an_array   # of length 3
        self.s = 3 

    def __mul__(self,that):
        tmp = [0]*self.s
        for i in range(self.s):
            tmp[i] = self.a[i]*that.a[i]
        return self.__class__(tmp)

    def __rmul__(self,that):
        tmp = [0]*self.s
        for i in range(self.s):
            tmp[i] = self.a[i]*that
        return self.__class__(tmp)      

so this works fine for a * b, b * a, 2*a, but not a*2!

2

There are 2 answers

3
wim On BEST ANSWER

You can not implement __rmul__ for both sides, because __rmul__ is, by definition, for right multiplication. When you want to change the behaviour of x * y you have to look at either x.__class__.__mul__ or y.__class__.__rmul__.

  • a * b uses R3.__mul__ (OK)
  • b * a also uses R3.__mul__ (OK)
  • 2 * a first uses int.__mul__, fails, then tries R3.__rmul__ instead (OK)
  • a * 2 uses R3.__mul__, fails, uses int.__rmul__, fails again (NOT OK!)

The way you have written it currently, __mul__ assumes that argument is an R3 instance, and __rmul__ assumes that argument is a scalar.

You can not modify int.__rmul__, to change the behaviour of the last case, because you can't patch those built-in types. However, you can modify your R3.__mul__ to change that behaviour.

You've implemented __mul__ to handle only R3 instances passed into that. Fix it so it can handle scalars passed into that aswell.

1
Morningstar Ndlovu On
class NumString:
    def __init__(self, value):
        self.value = str(value)

    def __str__(self):
         return self.value

    def __int__(self):
        return int(self.value)

    def __float__(self):
        return float(self.value)

    def __add__(self, other):
        if '.' in self.value:
            return float(self) + other
        return int(self) + other

    def __radd__(self, other):
        return self + other

    def __iadd__(self, other):
        self.value = self + other
        return self.value

    def __mu1__(self, other):
        if '.' in self.value:
            return float(self) * other
        return int(self) * other

    def __rmu1__(self, other):
        return self * value