Bug or intended behavior? (Posting On Python-List Prohibited)

Steve D'Aprano steve+python at pearwood.info
Fri Jun 9 07:52:13 EDT 2017


On Fri, 9 Jun 2017 02:13 pm, Lawrence D’Oliveiro wrote:

> On Sunday, June 4, 2017 at 9:59:11 AM UTC+12, Sean DiZazzo wrote:
>> Looking at operator precedence, I only see the % operator in regards to
>> modulus.  Nothing in regards to string formatting.
> 
> Operators in Python have no intrinsic meaning. They are just syntactic sugar
> for invoking methods with special names on the operand objects. 

That's wrong. The dunder methods are implementation, and are not intended to be
called directly. It is a myth that, for example:


> For example, 
> 
>     a % b
> 
> is just a cleaner way of writing
> 
>     a.__mod__(b)
>
> or, if object “a” does not support “__mod__”, but object “b” has “__rmod__”,
> then it means
> 
>     b.__rmod__(a)

That's wrong.

First error: in CPython 3, and in CPython 2 for new style classes, the
interpreter does not call a.__mod__ or b.__rmod__.

Instead, it calls type(a).__mod__ or type(b).__rmod__, which is not necessarily
the same thing.

Second error: it is not correct that b.__rmod__ is only called if a does not
support __mod__. That is a woefully incomplete description of what actually
occurs. Here is an approximate pseudo-code of what actually happens:


A = type(a)
B = type(b)
if issubclass(B, A) and hasattr(B, '__rmod__'):
    x = B.__rmod__(b, a)
    if x is NotImplemented:
        if hasattr(A, '__mod__'):
            x = A.__mod__(a, b)
            if x is NotImplemented:
                raise TypeError
            else:
                return x
    else:
        return x
elif hasattr(A, '__mod__'):
    x = A.__mod__(a, b)
    if x is NotImplemented:
        if hasattr(B, '__rmod__'):
            x = B.__mod__(b, a)
            if x is NotImplemented:
                raise TypeError
            else:
                return x
    else:
        return x
elif hasattr(B, '__rmod__'):
    x = B.__rmod__(b, a)
    if x is NotImplemented:
        assert not hasattr(A, '__mod__')
        raise TypeError
    else:
        return x
else:
    raise TypeError


The bottom line is, if you are calling dunder methods directly instead of
operators, you're probably doing it wrong.




-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list