Object-oriented 1

Rational

A rational is a number defined by a numerator and a denominator. The denominator should not be zero.

Step 1

A simple class for rationals (=fractions).

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

class Rational(object):

  def __init__(self, num, denom):
    self._n = num
    self._d = denom

  def __repr__(self):
    return "%d/%d" % (self._n, self._d)

R1 = Rational(1,2)
R2 = Rational(1,4)
R3 = Rational(5,7)

print "R1 = ", R1
print "R2 = ", R2
print "R3 = ", R3

Step 2

Let's add some accessors for the numerator and the denominator

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

class Rational(object):

  def __init__(self, num, denom):
    self.put(num, denom)

  def __repr__(self):
    return "%d/%d" % (self._n, self._d)

  def getNum(self):
    return self._n

  def putNum(self, num):
    self._n = num

  def getDenom(self):
    return self._d

  def putDenom(self, denom):
    self._d = denom

  def get(self):
    return self._n, self._d

  def put(self, num, denom):
    self.putNum(num)
    self.putDenom(denom)


R1 = Rational(1,2)
R2 = Rational(1,4)
R3 = Rational(5,7)

print "R1 = ", R1
print "R2 = ", R2
print "R3 = ", R3

R3.put(-7,13)
print "R3 = ", R3
print "R1.num = ", R1.getNum()
print "R1.denom = ", R1.getDenom()
R1.putNum(5)
R2.putDenom(3)
print "R1 = ", R1
print "R2 = ", R2
print "R3 = ", R3

Step 3

Hide all accessors in properties.

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

class Rational(object):
  __slots__  = ["__d", "__n"]

  def __init__(self, num, denom):
    self.frac = num, denom

  def __repr__(self):
    return "%d/%d" % (self.__n, self.__d)

  def __getNum(self):
    return self.__n

  def __putNum(self, num):
    self.__n = num

  def __getDenom(self):
    return self.__d

  def __putDenom(self, denom):
    if (denom == 0):
      raise ValueError("Denominator should not be 0")
    self.__d = denom

  def __put(self, t):
    self.num = t[0]
    self.denom = t[1]
  def __get(self):
    return self.__n, self.__d

  num = property(__getNum, __putNum)
  denom = property(__getDenom, __putDenom)
  frac = property(__get, __put)



R1 = Rational(1,2)
R2 = Rational(1,4)
R3 = Rational(5,7)

print "R1 = ", R1
print "R2 = ", R2
print "R3 = ", R3

R3.frac = -7, 13
print "R3 = ", R3
print "R1.num = ", R1.num
print "R1.denom = ", R1.denom
R1.num = 5
R2.denom = 3
print "R1 = ", R1
print "R2 = ", R2
print "R3 = ", R3

Step 4

Add the multiplication operation. This multiplication can be defined as a object method or a class (static) method1.

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

class Rational(object):
  __slots__  = ["__d", "__n"]

  def __init__(self, num, denom):
    self.frac = num, denom

  def __repr__(self):
    return "%d/%d" % (self.__n, self.__d)

  def __getNum(self):
    return self.__n

  def __putNum(self, num):
    self.__n = num

  def __getDenom(self):
    return self.__d

  def __putDenom(self, denom):
    if (denom == 0):
      raise ValueError("Denominator should not be 0")
    self.__d = denom

  def __put(self, t):
    self.num = t[0]
    self.denom = t[1]
  def __get(self):
    return self.__n, self.__d

  num = property(__getNum, __putNum)
  denom = property(__getDenom, __putDenom)
  frac = property(__get, __put)

  def mult(R1, R2):
    n = R1.num*R2.num
    d = R1.denom*R2.denom
    return Rational(n, d)
  mult = staticmethod(mult)


  def __mul__(self, other):
    n = self.num*other.num
    d = self.denom*other.denom
    return Rational(n, d)



R1 = Rational(1,2)
R2 = Rational(1,4)
R3 = Rational(5,7)

print "R1 = ", R1
print "R2 = ", R2
print "R3 = ", R3

R3.frac = -7, 13
print "R3 = ", R3
print "R1.num = ", R1.num
print "R1.denom = ", R1.denom
R1.num = 5
R2.denom = 3
print "R1 = ", R1
print "R2 = ", R2
print "R3 = ", R3
print "R1*R2 = ", Rational.mult(R1, R2)
print "R1*R2 = ", R1*R2

Step 5

Add documentation, clean the code so you can use it as a module.

  • Rational.py
#!/usr/bin/env python

# -*- coding: UTF-8 -*-

class Rational(object):
    """Rational class

A Rational is defined with a numerator (num) and
a denominator (denom). The denom attribute should not
be zero.
    """
    __slots__  = ["_d", "_n"]

    def __init__(self, num = 0, denom = 1):
    """Construtor. By default, a rational object is 0/1"""
    self.frac = num, denom

    def __repr__(self):
    """Representation of a fraction in the form "n/d"."""
    return "%d/%d" % (self._n, self._d)

    def _getNum(self):
    return self._n

    def _putNum(self, num):
    self._n = num

    def _getDenom(self):
    return self._d

    def _putDenom(self, denom):
    if (denom == 0):
      raise ValueError("Denominator should not be 0")
    self._d = denom

    def _put(self, t):
    self.num = t[0]
    self.denom = t[1]
    def _get(self):
    return self._n, self._d

    _num_doc = """Rational attribute corresponding to the numerator"""
    _dem_doc = """Rational attribute corresponding to the denominator"""
    _frc_doc = """Tuple (n, d) representing the rational numerator and denominator"""
    num = property(_getNum, _putNum, doc = _num_doc)
    denom = property(_getDenom, _putDenom, doc = _dem_doc)
    frac = property(_get, _put, doc = _frc_doc)

    def mult(R1, R2):
    """static method to multiply two rational numbers"""
    n = R1.num*R2.num
    d = R1.denom*R2.denom
    return Rational(n, d)
    mult = staticmethod(mult)


    def __mul__(self, other):
    """multiplication of a rational number by another"""
    n = self.num*other.num
    d = self.denom*other.denom
    return Rational(n, d)



if __name__ == "__main__":
    R1 = Rational(1,2)
    R2 = Rational(1,4)
    R3 = Rational(5,7)

    print "R1 = ", R1
    print "R2 = ", R2
    print "R3 = ", R3

    R3.frac = -7, 13
    print "R3 = ", R3
    print "R1.num = ", R1.num
    print "R1.denom = ", R1.denom
    R1.num = 5
    R2.denom = 3
    print "R1 = ", R1
    print "R2 = ", R2
    print "R3 = ", R3
    print "R1*R2 = ", Rational.mult(R1, R2)
    print "R1*R2 = ", R1*R2
  • pydoc Rational:
Help on module Rational:

NAME
    Rational - # -*- coding: UTF-8 -*-

FILE
    /home/gmonard/Ecrit/Conferences/2013/Ecole-CORREL-Paris/Python-Objet/Rational.py

CLASSES
    __builtin__.object
        Rational

    class Rational(__builtin__.object)
 | Rational class                                                        
 | --------------                                                        
 |                                                                       
 | A Rational is defined with a numerator (num) and                      
 | a denominator (denom). The denom attribute should not                 
 | be zero.                                                              
 |                                                                       
 | Methods defined here:                                                 
 |                                                                       
 | __init__(self, num=0, denom=1)                                        
 | Construtor. By default, a rational object is 0/1                      
 |                                                                       
 | __mul__(self, other)                                                  
 | multiplication of a rational number by another                        
 |                                                                       
 | __repr__(self)                                                        
 | Representation of a fraction in the form "n/d".                       
 |                                                                       
 | ----------------------------------------------------------------------
 | Static methods defined here:                                          
 |                                                                       
 | mult(R1, R2)                                                          
 | static method to multiply two rational numbers                        
 |                                                                       
 | ----------------------------------------------------------------------
 | Data descriptors defined here:                                        
 |                                                                       
 | denom                                                                 
 | Rational attribute corresponding to the denominator                   
 |                                                                       
 | frac                                                                  
 | Tuple (n, d) representing the rational numerator and denominator      
 |                                                                       
 | num                                                                   
 | Rational attribute corresponding to the numerator                     

Using the Rational module:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import Rational

R1 = Rational.Rational(1, 2)
R2 = Rational.Rational()
R2.frac = 2, 1
print "R1 = ", R1
print "R2 = ", R2
print "R1*R2 = %s" % (R1*R2)

  1. The difference between static and class methods in Python is beyond of this scope.