Why regular operations are not based on their in-place corresponding operation?

48 Views Asked by At

To me, the only difference is that the regular operation needs one more instantiation, and the result is held by this new instance. And thus the regular implementation should call the other.

But : these (in-place) methods should attempt to do the operation in-place (modifying self) and return the result (which could be, but does not have to be, self). If a specific method is not defined, or if that method returns NotImplemented, the augmented assignment falls back to the normal methods.

Here, i understand that the standard way is the opposite of mine : __iadd__ relies on __add__ EDIT in the sense that __add__ will be called in last resort.

So why __add__ is the default way to achieve the addition and not __iadd__, whereas it should require less processing ? END EDITING

A bit of context : the question came while implementing a Polynomial class, for learning purpose. I have written:

class A:
    ...
    def __iadd__(self, other):
        "processing resulting in modification of attributes of self"
        return self
    def __add__(self, other):
        res = self.copy() # A.copy() being implemented as well
        res += other
        return res
2

There are 2 best solutions below

0
M_R-B On BEST ANSWER

Inplace operations likely modify their operands. In the example you give, you use A.copy() to avoid that.

Some types do not allow modifications (tuples, for example, are immutable). Thus they don't allow inplace operations.

Also, inplace operations are not exactly intuitive to someone new to programming, or even to someone new to python. It's a nice feature of the language, but that's all.

Overall, regular operations are the 'normal' form of operations. If you're writing a new class and want to support operators, you'll probably think of the regular operators first, and the inplace ones later, or not at all. With your way, inplace would not work if only regular was defined.

But sometimes performance is indeed an issue, and inplace would allow for a more efficient implementation. That's why you have the possibility to define the inplace operation rather then just have it call the regular one.

0
no comment On

You misunderstood the documentation and confused the operators and the methods. It's not __iadd__ that calls __add__, it's the += operator (or rather the part of the interpreter that handles it) that calls it. That operator first tries to call __iadd__, and if that doesn't work (because __iadd__ doesn't exist or returns NotImplemented), then the operator tries __add__. That's what the documentation means.

It also wouldn't make sense for __iadd__ to call __add__ because that would create a new object which isn't needed.

When a type does implement __iadd__, then likely also __add__, and quite possibly __add__ does call __iadd__ after making a copy, just like you did. Or neither calls the other, and both call some "update" method, as for example OrderedDict.__ior__ and OrderedDict.__or__ do:

    def __ior__(self, other):
        self.update(other)
        return self

    def __or__(self, other):
        if not isinstance(other, dict):
            return NotImplemented
        new = self.__class__(self)
        new.update(other)
        return new