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

Guido van Rossum guido at python.org
Tue Oct 28 13:28:32 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

You're making a mountain of a molehill here, Alex.  I know that in
group theory there are non-Abelian groups (for which AB != BA), but
I've never encountered one myself in programming; more typical such
non-commutative operations are modeled as __add__ rather than as
__mul__.

Anyway, the real issue AFAICT is not that people depend on __rmul__'s
absence to raise a TypeError, but that people learn by example and
find __rmul__ isn't necessary by experimenting with integers.

The reason why it works at all for integers without __rmul__ is
complicated; it has to do with very tricky issues in trying to
implement multiplication of a sequence with an integer.  That code has
gone through a number of iterators, and every time someone eventually
found a bug in it, so I'd rather leave the __rmul__ blemish than
uproot it again.  If you can come up with a fix that doesn't break
sequence repetition I'd be open to accepting it (for 2.4 only, in 2.3
there may be too much code depending on the bug) but only after
serious review -- and not by me, because I'm not all that familiar
with all the subtleties of that code any more. :-(

--Guido van Rossum (home page: http://www.python.org/~guido/)



More information about the Python-Dev mailing list