[Python-Dev] Re: the "3*x works w/o __rmul__" bug

Alex Martelli aleaxit at yahoo.com
Tue Oct 28 10:39:08 EST 2003


On Tuesday 28 October 2003 04:16 pm, Guido van Rossum wrote:
> > So perhaps for 2.3 we should just apologetically note the anomaly
> > in the docs, and for 2.4 forbid the former case, i.e., require both
> > __mul__ AND __rmul__ to exist if one wants to code sequence
> > classes that can be multiplied by integers on either side...?
> >
> > Any opinions, anybody...?
>
> What's wrong with the status quo?  So 3*x is undefined, and it happens
> to return x*3.  Is that so bad?

Where is it specified that 3*x "is undefined" when x's type exposes
__mul__ but not __rmul__ ?  Sorry, I don't understand the viewpoint
you seem to imply here.  If x's type exposed no __add__ but "it just
so happened" that x+23 always returned 12345 -- while every other
addition, as expected, failed -- would you doubt the lack of a normal
and reasonably expected exception is bad?

I think that if Python returns "arbitrary" results, rather than raising an
exception, for operations that "should" raise an exception, that is
surely very bad -- it makes it that much harder for programmers to
debug the programs they're developing.  If there's some doubt about
the words I've put in hyphens -- that treating x*y just like y*x only for
certain values of type(y) isn't arbitrary or shouldn't raise -- then we
can of course discuss this, but isn't the general idea correct?

Now, the docs currently say, about sequences under
http://www.python.org/doc/current/ref/sequence-types.html :
"""
sequence types should implement ... multiplication (meaning repetition) by 
defining the methods __mul__(), __rmul__() and __imul__() described below; 
they should not define __coerce__() or other numerical operators.
"""
So, a sequence-emulating type that implements __mul__ but not __rmul__ 
appears to violate that "should".

The description of __mul__ and __rmul__ referred to seems to be
that at http://www.python.org/doc/current/ref/numeric-types.html .

It says that methods corresponding to operations not supported by
a particular kind of number should be left undefined (as opposed
to the behavior of _attempts at those operations_ being undefined),
so if I had a hypothetical number type X such that, for x instance
of X and an integer k, x*k should be supported but k*x shouldn't,
isn't this a recommendation to not write __rmul__ in X ...?


Besides, this weird anomaly is typical of newstyle classes only.
Consider:

>>> class X:
...   def __mul__(self, other): return 23
...
>>> x=X()
>>> x*7
23
>>> 7*x
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: unsupported operand type(s) for *: 'int' and 'instance'
>>>

ALL wonderful, just as expected, hunky-dory.  But now, having
read that newstyle classes are better, I want to make X newstyle --
can't see any indication in the docs that I shouldn't -- and...:

>>> class X(object):
...   def __mul__(self, other): return 23
...
>>> x=X()
>>> x*7
23
>>> 7*x
23
>>>

*eep*!  Yes, it DOES seem to be that this is QUITE bad indeed.


Alex




More information about the Python-Dev mailing list