new-style classes multiplication error message isn't very informative

Jon Guyer guyer at nist.gov
Thu Dec 29 22:47:30 EST 2005


>>> This is a fake line to confuse the stupid top-posting filter at gmane

We have a rather complicated class that, under certain circumstances, knows
that it cannot perform various arithmetic operations, and so returns
NotImplemented.  As a trivial example:

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

This error message isn't hugely meaningful to many of our users (and in
complicated expressions, I'd certainly benefit from knowing exactly which
subclasses of 'my' are involved), but it beats the behavior with new-style
classes:

    >>> class my(object):
    ...     def __mul__(self, other):
    ...             return NotImplemented
    ... 
    >>> my() * my()
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    TypeError: can't multiply sequence to non-int

After a lot of googling and a lot of pouring over abstract.c, I now
understand that object() is defined with a tp_as_sequence, and so the error
message is the result of the last-ditch effort to do sequence concatentation.

What if I don't want to permit sequence concatenation? 
Is there a way to unset tp_as_sequence?
Should I be inheriting from a different class?  We started inheriting from
object because we want a __new__ method.

The "'instance' and 'instance'" message would be OK, but even better is the
result of this completely degenerate class:

    >>> class my(object):
    ...     pass
    ... 
    >>> class your(my):
    ...     pass
    ... 
    >>> my() * your()
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    TypeError: unsupported operand type(s) for *: 'my' and 'your'

That's an error message I can actually do something with.  Is there any way
to get this behavior when I do have a __mul__ method and sometimes return
NotImplemented?

We're doing most of our development in Python 2.3, if it matters.




More information about the Python-list mailing list