title: How to (Sanely) Extend sympy.Rational
body: <p>Is there a sane way to get and use MixedNumbers in sympy instead of improper fractions? (I'm using the latex output and generating pdfs for grade schoolers with problems like 1 3/4 + 2 1/3 = ?)</p>
  
  <p>I am trying to create a MixedRational (or MixedNumber or MixedFraction) class for use in SymPy.
  <a href="http://osdir.com/ml/python-sympy/2011-12/msg00082.html" rel="nofollow">This</a> is the only thread related to mixed representations in SymPy that I was able to find.</p>
  
  <p>I want my MixedRational class to have 2 member variables: i and f, for the integral and fractional part of the mixed number, and have appropriate methods like <code>__str__</code> so that it gets printed as a mixed number.</p>
  
  <p>However, I have been unable to overcome the first hurdle in this path, namely the ability to subclass Rational at all. Overriding <code>__new__</code> seems to be a requirement, since <code>Rational.__new__(cls, *args)</code> returns an instance of whatever type it feels like, instead of returning an instance of type cls (why Attempt 0 failed). </p>
  
  <p>I have creating a new Rational based on the provided args and storing it inside the MixedNumber, and somehow transparently passing through accesses to functions and variables that MixedNumber does not define (Attempt 1,2,3), but I have not had success with any of the methods I've tried.</p>
  
  <p>Since I can get a subclass of Rational to behave sanely when <code>Rational.__new__(cls, *args)</code> would actually return a Rational (instead of Integer or One or Zero), I am almost ready to write 5 separate classes (MixedNumber, MixedRational, MixedInteger, MixedOne, MixedZero), with <code>MixedNumber.__new__(cls, *args)</code> calling <code>Rational.__new__(cls, *args)</code> and then deciding which Mixed* class to instantiate based on the type <code>Rational.__new__</code> returns.</p>
  
  <p>I feel like I have to be overcomplicating this, however. </p>
  
  <pre><code>from sympy import *
  class MixedNumber(Rational):
      def __new__(cls, *args):
          #Attempt 3
          rational_instance = Rational.__new__(cls, *args)
          rational_instance.__class__ = cls
          return rational_instance
  
          #Attempt 2
          #rational_instance = Rational.__new__(cls, *args)
          #mixed_instance = object.__new__(cls)
          #mixed_instance.my_rational = rational_instance
          #print("dict")
          #return mixed_instance
  
          #Attempt 1
          #rational_instance = Rational.__new__(cls, *args)
          #mixed_instance = object.__new__(cls)
          #mixed_instance.__dict__.update(rational_instance.__dict__)
          #return mixed_instance
  
          #Attempt 0
          #return Rational.__new__(cls, *args)    
      def __init__(self, *args):
          # print(self.__dict__)
          # print(self.my_rational)
          self.my_rational.__init__(*args)
      #Attempt 2  
      #def __getattr__(self, attr):
      #   print("Attr=", attr)
      #   print("Dict=",self.__dict__)
      #   import time
      #   time.sleep(1)
      #   try:
      #       return self.__dict__[attr]
      #   except KeyError:
      #       return getattr(self.my_rational, attr)
  x = Rational(0,1)
  print(x)
  print(type(x))
  print(x.p)
  print(x.q)
  y = Rational(3,1)
  print(y)
  print(type(y))
  print(y.p)
  print(y.q)
  z = Rational(15,4)
  print(z)
  print(type(z))
  print(z.p)
  print(z.q)
  x = MixedNumber(0,1)
  print(x)
  print(type(x))
  print(x.p)
  print(x.q)
  y = MixedNumber(3,1)
  print(y)
  print(type(y))
  print(y.p)
  print(y.q)
  z = MixedNumber(15,4)
  print(z)
  print(type(z))
  print(z.p)
  print(z.q)
  </code></pre>