Python: Can I have instances of returning a subclass of my own type for statements defined in a superclass?

In Python (2.7), I want to create a class of rational numbers that mimics the behavior of the Fraction class (in modular fractions), but overrides the __repr__ method to match the result of __str__. The original idea was only for my own messing around, and just to make the IDLE result look more friendly. But now I'm more interested in understanding the basic inheritance / typing problem, which, in my opinion, may be of general interest, as opposed to getting a workaround for this particular use case, which is admittedly trivial.

The problem is that I would like to inherit the functionality of all numeric operators (__add__, __sub__ methods, etc.), but there are results as instances of my subclass, not fractions. This is what I want, but instead it happens:

class Q(Fraction):
    def __repr__(self):
        return str(self)

>>> Q(1,2)
1/2
>>> Q(1,2) + Q(1,3)
Fraction(5, 6)

This is because the operators defined in Fraction return instances of Fraction. Of course, I could redefine all these magic methods individually, calling the parent class to do the math, and then forcing my type, but I believe there should be a way to deal with this repetitive situation as a whole (i.e. without spelling "def" 20 times).

__getattribute__ , , , , . ( , __getattr__ , , , , !)

, , , ?

+4
1

, . - , , int, . , int, (, , , ints , ...). , , , :

# I stole this decorator from another stackoverflow recipe :) 
def returnthisclassfrom(specials):
  specialnames = ['__%s__' % s for s in specials.split()]
  def wrapit(cls, method):
    return lambda *a: cls(method(*a))
  def dowrap(cls):
    for n in specialnames:
      method = getattr(cls, n)
      setattr(cls, n, wrapit(cls, method))
    return cls
  return dowrap

def int_getslice(self, i, j):
    # NON-pythonic, will return everything inclusive i.e. x[5:3] returns 3 bits, not 2.
    # Because that what users normally expect.
    # If you're a purist, modify below.
    if i > 1000000 or j > 1000000:
        raise ValueError, 'BitSize limited to 1 million bits'
    lo = min(i,j)
    hi = max(i,j)
    mask = (1<<((hi-lo)+1))-1

    return (self>>lo) & mask

def int_getitem(self, i):
    # Safety limit
    if i > 1000000:
        raise ValueError, 'BitSize limited to 1 million bits'
    return (self>>i)&1

def int_iter(self):
    # since getitem makes it iterable, override
    raise AttributeError, 'int object is not iterable'

@returnthisclassfrom('abs add and div floordiv lshift mod mul neg or pow radd rand rdiv rdivmod rfloordiv rlshift rmod rmul ror rpow rrshift rshift rsub rxor rtruediv sub truediv xor trunc')
class BitSliceInt(long):
  __getslice__ = int_getslice
  __getitem__ = int_getitem
  __iter__ = int_iter
+1

All Articles