3

I have this class which works with fractions (e.g. (1,2), (3,4) etc):

class Fraction(object):

    def __init__(self, num=0, denom=1):
        ''' Creates a new Fraction with numberator num and denominator denom'''
        self.numerator = num
        if denom != 0:
            self.denominator = denom
        else: 
            raise ZeroDivisionError
    def __str__(self):
        '''Returns the string numerator/denominator '''
        return "{0}/{1}".format(self.numerator, self.denominator)
    def __repr__(self):
        """blah"""
        return Fraction(self.numerator, self.denominator)

And I want to have a sub-class Mixed number which can accept both a whole number and a fraction (e.g. 2 Fraction(1,2), 3 Fraction (3,4) etc). I'm not sure how to do this however, Any help as to how to do this would be appreciated

class MixedNumber(Fraction):
user2101517
  • 700
  • 3
  • 11
  • 22
  • 4
    I don't think it makes sense for `MixedNumber` to inherit from `Fraction`. It would make more sense to *compose* a `Fraction` into the `MixedNumber` class. – Hunter McMillen May 23 '13 at 03:43
  • I agree with @HunterMcMillen, but just for the record, the syntax you use at the end of your post is exactly right for inheriting in Python. Maybe I don't understand what you're asking or what problem you're facing; could you clarify? – jpmc26 May 23 '13 at 04:05
  • 1
    Subclass always means a 'is a' relationship. So `MixedNumber` seems not suitable to inherit from `Fraction`. – zhangyangyu May 23 '13 at 04:12

2 Answers2

5

There are two ways that immediately come to mind when thinking of implementing a MixedNumber class with a Fraction class provided. One way is as @HunterMcMillen suggests, is to have the class use composition, which is to utilize distinct objects to represent the whole number, and fraction parts, respectively. This gives you access to each objects specialized methods inside your class, which can be handy if the components you're building from have distinct behaviors each encapsulates.

class MixedNumber(object):
   def __init__(self, whole_number, fraction):
        self.whole_number = whole_number
        self.fraction = fraction

   def __str__(self):
        if self.fraction.numerator == 0:
            return str(self.whole_number)
        elif self.whole_number == 0:
            return str(self.fraction)
        else:
            return '{} {}'.format(self.whole_number,self.fraction)

   def __repr__(self):
        return 'MixedNumber({},{!r})'.format(self.whole_number,self.fraction)

The other possibility is inheritance, if your Fraction class supports improper fractions, then you can use a subclass to appropriately handle initialization and string rendering in mixed number format, as follows:

class MixedNumber(Fraction):
    def __init__(self, whole_number, fraction):     
        num = whole_number * fraction.denominator + fraction.numerator
        super(MixedNumber,self).__init__(num,  fraction.denominator)

    def __str__(self):
        # assume positive fractions for demonstration only
        q, r = divmod(self.numerator,self.denominator)
        if r == 0:
            return str(q)
        elif q == 0:
            return super(MixedNumber,self).__str__() 
        else:
            return '{} {}/{}'.format(q,r,self.denominator)

    def __repr__(self):
        q, r = divmod(self.numerator, self.denominator)
        return 'MixedNumber({},Fraction({},{}))'.format(q,r,self.denominator)

Your Fraction.__repr__ method should return a string that when passed into eval should instantiate something equal to the source object, i.e. eval(frac) == frac. See this stack overflow question for more details on the distinction between __str__ and __eval__.

Community
  • 1
  • 1
mtadd
  • 2,495
  • 15
  • 18
0

I recently finished writing class Mixed that inherits from the standard library Fraction class. It would probably be a good guide on how to use existing functionality of the parent class. The source is HERE. It accepts as input anything that the library Fraction class accepts as well as string representations of mixed numbers such as Mixed('3 4/5') or rational whole_number/numerator/denominator sets as in Mixed(3,4,5). All of the functionality of Fraction has been preserved. __str__ and __repr__ would yield 3 4/5 and Mixed(3,4,5) respectively. It makes conversion to float or standard Fraction as easy as float(m) or Fraction(m). Cheers

JB0x2D1
  • 838
  • 8
  • 20