Open In App

__rmul__ in Python

Last Updated : 04 May, 2020
Improve
Improve
Like Article
Like
Save
Share
Report

For every operator sign, there is an underlying mechanism. This underlying mechanism is a special method that will be called during the operator action. This special method is called magical method. For every arithmetic calculation like +, -, *, /, we require 2 operands to carry out operator functionality.

Examples:

‘+’ ? ‘__add__’ method
‘_’ ? ‘__sub__’ method
‘*’ ? ‘__mul__’ method

As the article is limited to multiplication functionality, we will see about multiplication procedure here. To perform the multiplication functionality, we have to tie up the operator sign to either left/right operand. Before, going to __rmul__ method, we will see about __mul__ method, which helps us to understand multiplication functionality vividly.

__mul__()

Let’s take an expression x*y where x is an instance of a class A. To perform the __mul__ method, the operator looks into the class of left operand(x) for the present of __mul__ i.e., operator(*) will check the class A for the presence of ‘__mul__’ method in it. If it has __mul__ method, it calls x.__mul__(y). Otherwise, it throws the ‘TypeError: unsupported operands’ error message.

Example 1:




class Foo(object):
      
    def __init__(self, val):
        self.val = val
          
    def __str__(self):
        return "Foo [% s]" % self.val
  
class Bar(object):
      
    def __init__(self, val):
        self.val = val
  
    def __str__(self):
        return "Bar [% s]" % self.val
  
# Driver Code
f = Foo(5)
b = Bar(6)
print(f * b)


Output:

TypeError, unsupported operand type(s) for *: 'Foo' and 'Bar'

In the above example, the first operand is f and its class Foo(). As Foo() has no __mul__ method, it doesn’t understand how to multiply. So, it will show up TypeError message. If we check the other class Bar(), even it has no __mul__ method. So, even if we reverse the multiplication to (b*f), it will throw the same error

Example 2: Lets add the __mul__ method in Foo class.




class Foo(object):
      
    def __init__(self, val):
        self.val = val
          
    def __mul__(self, other):
        return Foo(self.val * other.val)
  
    def __str__(self):
        return "Foo [% s]" % self.val
  
class Bar(object):
      
    def __init__(self, val):
        self.val = val
  
    def __str__(self):
        return "Bar [% s]" % self.val
  
# Driver Code
f = Foo(5)
b = Bar(6)
print(f * b)


Output:

Foo 30

As it is already mentioned, the operator by default looks into the left operand’s class, and here it finds the __mul__ method. Now it knows what to do and resulted 30 f.__mul__(b) = 5.__mul__(6). If we reverse the multiplication to (b*f), it throws up the issue again, as it looks into left operand’s class(Bar()) which doesn’t have any __mul__ method. b.__mul__(f) will throws the issue as b’s class Bar() doesn’t have __mul__ method.

__rmul__

A slight difference between __mul__ and __rmul__ is, Operator looks for __mul__ in left operand and looks for __rmul__ in right operand. For example, x*y. Operator looks for __rmul__ method in the y’s class definition. If it finds the __rmul__ method, it will show up with the result, otherwise throws the TypeError error message

Example 1: Let’s take the above example with a small modification.




class Foo(object):
      
    def __init__(self, val):
        self.val = val
  
    def __str__(self):
        return "Foo [% s]" % self.val
  
  
class Bar(object):
      
    def __init__(self, val):
        self.val = val
  
    def __rmul__(self, other):
        return Bar(self.val * other.val)
  
    def __str__(self):
        return "Bar [% s]" % self.val
  
# Driver code
f = Foo(5)
b = Bar(6)
  
print(f * b)


Output:

Bar 30

In the above example, it assumes f*b as b.__rmul__(f) as __rmul__ method is present in Bar() class of the instance b. If we reverse the multiplication to (b*f). The notation will be f.__rmul__(b). If it doesn’t have __rmul__ method, it can’t understand what to notate and throws up TypeError message.’

These type of operators, that require 2 operands, it will by default carry both __mul__ and __rmul__ method. To perform multiplication with both normal and reverse multiplication, see the below example.

Example 2:




class Foo(object):
      
    def __init__(self, val):
        self.val = val
  
    def __str__(self):
        return "Foo [% s]" % self.val
  
  
class Bar(object):
      
    def __init__(self, val):
        self.val = val
  
    def __rmul__(self, other):
        return Bar(self.val * other.val)
  
    def __mul__(self, other):
        return self.__rmul__(other)
  
    def __str__(self):
        return "Bar [% s]" % self.val
  
  
# Driver Code
f = Foo(5)
b = Bar(6)
  
print(b * f)
print(f * b)


Output:

Bar [30]
Bar [30]


Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads