Addition and multiplication puzzle

Emile van Sebille emile at fenx.com
Sat Oct 25 13:33:38 EDT 2003


"Mark Dickinson" <marketdickinson at yahoo.com> wrote in message
news:mailman.90.1067096689.702.python-list at python.org...
> Can anyone either reproduce or explain the following
> apparently inconsistent behaviours of __add__ and
> __mul__?  The class Gaussian provides a sub-bare-bones
> implementation of Gaussian integers (a Gaussian
> integer is a complex number x+yi for which both x and
> y are
> integers):
>
> class Gaussian(object):
>     """class representing Gaussian integers"""
>
>     def __init__(self, x, y = 0):
>         self.real, self.imag = x, y
>
>     def __repr__(self):
>         return repr(self.real) + "+" + repr(self.imag)
> + "*i"
>
>     def __add__(self, other):
>         if type(other) != Gaussian:
>             other = Gaussian(other)
>         return Gaussian(self.real + other.real,
> self.imag + other.imag)
>
>     def __mul__(self, other):
>         if type(other) != Gaussian:
>             other = Gaussian(other)
>         return Gaussian(self.real * other.real -
> self.imag * other.imag, \
>                           self.real * other.imag +
> self.imag * other.real)
>
> Under Python 2.3.2 I get:
>
> >>> i = Gaussian(0, 1)
> >>> i * 3
> 0+3*i
> >>> 3 * i   # surprise!
> 0+3*i
> >>> i + 3
> 3+1*i
> >>> 3 + i
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> TypeError: unsupported operand type(s) for +: 'int'
> and 'Gaussian'
>
> In other words, I can *multiply* an int by a Gaussian
> in either order, but I can only *add* a Gaussian to an
> int, not the other way around.  The surprise is that
> multiplying an int by a Gaussian works---I'd expect it
> to complain since there's no __rmul__ method defined,
> in just the same way that 3+i produced an exception
> above.  Why do addition and multiplication behave
> differently?

I think new style classes create this, as old style classes exhibit the same
behaviour for multiplication and division:

class Test:
    def __init__(self, val):
        self.val = val
    def __add__(self, other):
        return self.val + other
    def __mul__(self, other):
        return self.val * other

In typeobject.c,  I find:

 SQSLOT("__add__", sq_concat, slot_sq_concat, wrap_binaryfunc,
        "x.__add__(y) <==> x+y"),
 SQSLOT("__mul__", sq_repeat, slot_sq_repeat, wrap_intargfunc,
        "x.__mul__(n) <==> x*n"),
 SQSLOT("__rmul__", sq_repeat, slot_sq_repeat, wrap_intargfunc,
        "x.__rmul__(n) <==> n*x"),

My guess is that this explains why multiplication works and addition
doesn't, as there is no corresponding SQSLOT("__radd__"...  but adding

 SQSLOT("__radd__", sq_concat, slot_sq_concat, wrap_binaryfunc,
        "x.__radd__(y) <==> y+x"),

and recompiling didn't fix the problem, so I'm either on the wrong track or
missed a connection along the way.

Emile van Sebille
emile at fenx.com








More information about the Python-list mailing list