[Swig-dev] Re: [Python-Dev] Operator overloading inconsistency (bug or feature?)

Marcelo Matus mmatus@dinha.acms.arizona.edu
Thu, 08 Aug 2002 08:17:24 -0700


Guido van Rossum wrote:

>>Suppose that a new-style class wants to overload "*" and it
>>defines two methods like this:
>>
>>class Foo(object):
>>    def __mul__(self,other):
>>        print "__mul__"
>>    def __rmul__(self,other):
>>        print "__rmul__"
>>
>>Python-2.2.1, if you try this, you get the following behavior:
>> 
>>    
>>
>>>>>f = Foo()
>>>>>f*1.0
>>>>>          
>>>>>
>>__mul__
>>    
>>
>>>>>1.0*f
>>>>>          
>>>>>
>>__rmul__
>>    
>>
>>>>>f*1
>>>>>          
>>>>>
>>__mul__
>>    
>>
>>>>>1*f
>>>>>          
>>>>>
>>__mul__
>>
>>So here is the question: Why does the last statement in this example
>>not invoke __rmul__?  In other words, why do "1.0*f" and "1*f" produce 
>>different behavior.  Is this intentional?  Is this documented someplace?
>>Is there a workaround?  Or are we just missing something obvious?
>>    
>>
>
>Aargh.  I *think* this may have to do with the hacks for sequence
>repetition.  But I'm not sure.  A debug session tracing carefully
>through the code is in order.
>
>--Guido van Rossum (home page: http://www.python.org/~guido/)
>
>  
>

I guess the problem arise from here:


intobject.c(340):
========================
static PyObject *
int_mul(PyObject *v, PyObject *w)
{
    long a, b;
    long longprod;            /* a*b in native long arithmetic */
    double doubled_longprod;    /* (double)longprod */
    double doubleprod;        /* (double)a * (double)b */

    if (!PyInt_Check(v) &&
        v->ob_type->tp_as_sequence &&
        v->ob_type->tp_as_sequence->sq_repeat) {
        /* sequence * int */
        a = PyInt_AsLong(w);
        return (*v->ob_type->tp_as_sequence->sq_repeat)(v, a);
    }
    if (!PyInt_Check(w) &&
        w->ob_type->tp_as_sequence &&
        w->ob_type->tp_as_sequence->sq_repeat) {
        /* int * sequence */
        a = PyInt_AsLong(v);
        return (*w->ob_type->tp_as_sequence->sq_repeat)(w, a);  
    }
    .............


==================

and the facts that:

1.-  there is only one 'sq_repeat' method, and not an addittional 
'sq_rrepeat' one,
      so,  n*x and x*n call the same method sq_repeat.

2.- in typeobect.c, sq_repeat is associated with __mul__

line 2775:
      SLOT1(slot_sq_repeat, "__mul__", int, "i")

line 3497:
    SQSLOT("__mul__", sq_repeat, slot_sq_repeat, wrap_intargfunc,
           "x.__mul__(n) <==> x*n"),

3.- the 'object' class by default enable the "tp_as_sequence" attribute,
triggering the call of sq_repeat in the case

       1*c

but not in

       1.0*c
  



Marcelo