9

I have a vector class:

class Vector: def __init__(self, x, y): self.x, self.y = x, y def __str__(self): return '(%s,%s)' % (self.x, self.y) def __add__(self, n): if isinstance(n, (int, long, float)): return Vector(self.x+n, self.y+n) elif isinstance(n, Vector): return Vector(self.x+n.x, self.y+n.y) 

which works fine, i.e. I can write:

a = Vector(1,2) print(a + 1) # prints (2,3) 

However if the order of operation is reversed, then it fails:

a = Vector(1,2) print(1 + a) # raises TypeError: unsupported operand type(s) # for +: 'int' and 'instance' 

I understand the error: the addition of an int object to an Vector object is undefined because I haven't defined it in the int class. Is there a way to work around this without defining it in the int (or parent of int) class?

1

2 Answers 2

10

You need to also define __radd__

Some operations do not necessarily evaluate like this a + b == b + a and that's why Python defines the add and radd methods.

Explaining myself better: it supports the fact that "int" does not define a + operation with class Vector instances as part of the operation. Therefore vector + 1 is not the same as 1 + vector.

When Python tries to see what the 1.__add__ method can do, an exception is raised. And Python goes and looks for Vector.__radd__ operation to try to complete it.

In the OP's case the evaluation is true and suffices with __radd__ = __add__

class Vector(object): def __init__(self, x, y): self.x, self.y = x, y def __str__(self): return '(%s,%s)' % (self.x, self.y) def __add__(self, n): if isinstance(n, (int, long, float)): return Vector(self.x+n, self.y+n) elif isinstance(n, Vector): return Vector(self.x+n.x, self.y+n.y) __radd__ = __add__ a = Vector(1, 2) print(1 + a) 

Which outputs:

(2,3) 

The same applies to all number-like operations.

Sign up to request clarification or add additional context in comments.

6 Comments

Maybe some more explanation is needed here?
is it similar for __mul__, __div__, etc? so __rmul__, __rdiv__, etc?
Yes if the first object in the operation (everything is an object) does not support the operation with the 2nd object
good answer, I'm accepting this answer mainly because of the hint __radd__=__add__, i like one-line solutions :)
In your case it is the solution ;)
|
4

When you say x + y, Python calls x.__add__(y). If x does not implement __add__ (or that method returns NotImplemented), Python tries to call y.__radd__(x) as a fallback.

Thus all you have to do is to define the __radd__() method in your Vector class and 1 + y will work as you would expect.

Note: you would have to do similar for other operations too, e.g. implement __mul__() and __rmul__() pair, etc.

You might also want to look at this question, it explains the same principle in more details.

Update: Depending on your use case, you might also want to implement the __iadd__() method (and its cousins) to override the += operator.

For example, if you say y += 1 (y being an instance of Vector here), you might want to modify the y instance itself, and not return a new Vector instance as a result, which what your __add__() method currently does.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.