# bestfraction.py # Walker M. White (wmw2) # October 7, 2012 """Module with a simple Fraction class. This module shows off operator overloading. This allows us to define complex mathematical objects. This version of Fraction has properties, which allow us to enforce our invariants. This is the prefered way to make a class in Python""" import math def _gcd(a,b): """Returns: Greatest common divisor of x and y. Precondition: x and y are integers.""" assert type(a) == int,`x`+' is not an int' assert type(b) == int,`y`+' is not an int' while b != 0: t = b b = a % b a = t return a class Fraction(object): """Instance is a fraction n/d""" # FIELDS _numerator = 0 # must be an int _denominator = 1 # must be an int > 0 # PROPERTIES @property # getter def numerator(self): """Fraction numerator. Invariant: Must be an int.""" return self._numerator # returns the field @numerator.setter # setter def numerator(self,value): # enforce invariant assert type(value) == int, `value`+' is not an int' # assign to field self._numerator = value @property # getter def denominator(self): """Fraction denominator. Invariant: Must be an int > 0.""" return self._denominator # returns the field @denominator.setter # setter def denominator(self,value): # enforce invariant assert type(value) == int, `value`+' is not an int' assert value > 0, `value`+' is not positive' # assign to field self._denominator = value # CONSTRUCTOR def __init__(self,n=0,d=1): """Constructor: Creates a new Fraction n/d Precondition: n an int, d > 0 an int.""" # No need for asserts; setters handle everything self.numerator = n self.denominator = d # OPERATORS def __str__(self): """Returns: this Fraction as a string 'n/d'""" return str(self.numerator)+'/'+str(self.denominator) def __repr__(self): """Returns: unambiguous representation of Fraction""" return str(self.__class__)+'['+str(self)+']' def __mul__(self,other): """Returns: Product of self and other as a new Fraction Does not modify contents of self or other Precondition: other is a Fraction""" assert type(other) == Fraction top = self.numerator*other.numerator bot = self.denominator*other.denominator return Fraction(top,bot) def __add__(self,other): """Returns: Sum of self and other as a new Fraction Does not modify contents of self or other Precondition: other is a Fraction""" assert type(other) == Fraction bot = self.denominator*other.denominator top = (self.numerator*other.denominator+ self.denominator*other.numerator) return Fraction(top,bot) def __eq__(self,other): """Returns: True if self, other are equal Fractions. False if not equal, or other not a Fraction""" if type(other) != Fraction: return False # Cross multiply left = self.numerator*other.denominator rght = self.denominator*other.numerator return left == rght def __ne__(self,other): """Returns: False if self, other are equal Fractions. True if not equal, or other not a Fraction""" return not self == other def __cmp__(self,other): """Returns: a negative integer if self < other, zero if self == other, a positive integer if self > other Used to implement comparison operations. Precondition: other is a Fraction.""" assert type(other) == Fraction # Cross multiply left = self.numerator*other.denominator rght = self.denominator*other.numerator return left - rght # NORMAL METHODS def reduce(self): """Normalizes this fraction so that numerator and denominator have no common divisors.""" g = gcd(self.numerator,self.denominator) self.numerator = self.numerator/g self.denominator = self.denominator/g