Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overloading operators for operands of different types in Python

Consider the following example of a 'wrapper' class to represent vectors:

class Vector:

    def __init__(self, value):
        self._vals = value.copy()


    def __add__(self, other):

        if isinstance(other, list):
            result = [x+y for (x, y) in zip(self._vals, other)]
        elif isinstance(other, Vector):
            result = [x+y for (x, y) in zip(self._vals, other._vals)]
        else:
            # assume other is scalar
            result = [x+other for x in self._vals]

        return Vector(result)

    def __str__(self):
        return str(self._vals)

The __add__ method takes care of adding two vectors as well as adding a vector with a scalar. However, the second case is not complete as the following examples show:

>>> a = Vector([1.2, 3, 4])
>>> print(a)
[1.2, 3, 4]
>>> print(a+a)
[2.4, 6, 8]
>>> print(a+5)
[6.2, 8, 9]
>>> print(5+a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'Vector'

To my understanding the reason is that the overloaded operator only tells Python what to do when it sees a + x where a is an instance of Vector, but there is no indication of what to do for x + a (with a an instance of Vector and x a scalar).

How one should overload the operators in such circumstances to cover all cases (i.e., to support the case that self is not an instance of Vector but other is)?

like image 997
MikeL Avatar asked Dec 03 '25 00:12

MikeL


1 Answers

Ok. I guess I found the answer: one has to overload __radd__ operator as well:

class Vector:

    def __init__(self, value):
        self._vals = value.copy()


    def __add__(self, other):

        if isinstance(other, list):
            result = [x+y for (x, y) in zip(self._vals, other)]
        elif isinstance(other, Vector):
            result = [x+y for (x, y) in zip(self._vals, other._vals)]
        else:
            # assume other is scalar
            result = [x+other for x in self._vals]

        return Vector(result)

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


    def __str__(self):
        return str(self._vals)

Although to me this looks a bit redundant. (Why Python does not use the commutativity of addition by default, assuming __radd__(self, other) always returns self + other? Of course for special cases the user can override __radd__.)

like image 98
MikeL Avatar answered Dec 04 '25 14:12

MikeL



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!