Usefulness of subclassing builtin number types

Gerhard Häring gerhard.haering at gmx.de
Sun Dec 15 11:54:28 EST 2002


I'd like to subclass some builtin number types, and int in particular.
And I want (of course) that this subclassing is 'sticky', so if I do a:

    x = MyInt(25)
    x *= 2

I want 'x' to stay of the class MyInt. I even can't think of any use
case right now where I'd *not* want this. The problem? Python doesn't do
this, instead it always returns ints.

Ok, I know that this saves one indirection per operation and is thus a
performance gain for int itself, as long as it's not subclassed. But
*if* it is subclassed, this behaviour is really a pain in the arse.

My current experimentation lead me to this code:

#v+
from __future__ import division

class StickyInt(int):
    __slots__ = []

    def __iadd__(self, other):
        return self.__class__(int.__radd__(self, other))

    def __add__(self, other):
        return self.__class__(int.__add__(self, other))

    def __sub__(self, other):
        return self.__class__(int.__sub__(self, other))

    def __mul__(self, other):
        return self.__class__(int.__mul__(self, other))

    def __div__(self, other):
        return self.__class__(int.__div__(self, other))

    def __divmod__(self, other):
        return map(self.__class__, int.__divmod__(self, other))

    def __mod__(self, other):
        return self.__class__(int.__mod__(self, other))

    def __pow__(self, other, modulus=None):
        return self.__class__(int.__pow__(self, other, modulus))
    
    def __floordiv__(self, other):
        return self.__class__(int.__floordiv__(self, other))

    def __abs__(self):
        return self.__class__(int.__abs__(self))

    def __pos__(self):
        return self.__class__(int.__pos__(self))

    def __neg__(self):
        return self.__class__(int.__neg__(self))

    def __nonzero__(self):
        return self.__class__(int.__nonzero__(self))

    def __invert__(self):
        return self.__class__(int.__invert__(self))

    def __or__(self, other):
        return self.__class__(int.__or__(self, other))

    def __and__(self, other):
        return self.__class__(int.__and__(self, other))

    def __xor__(self, other):
        return self.__class__(int.__xor__(self, other))

    def __lshift__(self, other):
        return self.__class__(int.__lshift__(self, other))

    def __rshift__(self, other):
        return self.__class__(int.__rshift__(self, other))

    # Behaviour of superclass is ok for __truediv__, __complex__, __int__,
    # __long__, __float__, __oct__, __hex__, __cmp__, __str__, __repr__

class MyInt(StickyInt):
    pass

if __name__ == "__main__":
    x = MyInt(25000)
    x = abs(x + 1)
    print type(x), x
print x+1
#v-

... which is a little *cough* more verbose than I'd want it to be. To
be honest, other than issubclass(MyInt, int) is now true I don't think
this gives me *any* advantage over previous versions of Python.

Questions:
1) should the behaviour be changed and the necessary additional
   indirection introduced for builtin types?

2) if not, and there are performance reasons for keeping it like it
   is, should something like my StickyInt be put into the Python 
   library?

3) or am I boldly going where no Python programmer has gone before?
   ;-) [1]

Gerhard

[1] looking forward to Star Trek - Nemesis :)
-- 
Favourite database:             http://www.postgresql.org/
Favourite programming language: http://www.python.org/
Combine the two:                http://pypgsql.sf.net/




More information about the Python-list mailing list