# Exercises: Series III¶

## Rational numbers (with correction)¶

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

### Step1¶

A simple class for rationals (=fractions).

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #!/usr/bin/env python3 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) 

### Step2¶

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

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #!/usr/bin/env python3 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.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #!/usr/bin/env python3 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) method (the difference between static and class methods in Python is beyond of this scope.).

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #!/usr/bin/env python3 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.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 #!/usr/bin/env python3 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
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:

  1 2 3 4 5 6 7 8 9 10 #!/usr/bin/env python3 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)) 

## Polar points¶

A polar point on a plane can be defined a distance from the origin and an angle (in degree).

### Step 1¶

Write a simple ''Polar'' class.

Skeleton:

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #!/usr/bin/env python3 import math # to convert degrees in radians class Polar(object): def __init__(self, r, degree): pass # ADD YOUR CODE HERE def putPolar(self, r, degree): pass # ADD YOUR CODE HERE def __repr__(self): pass # ADD YOUR CODE HERE P1 = Polar(1.0, 180.0) P2 = Polar(3.0, 90.0) print("P1 = ", P1) print("P2 = ", P2) 

Solution

### Step 2¶

import math

class Polar(object):
def __init__(self, r, degree):
"""Polar constructor"""
pass

def putPolar(self, r, degree):
"""Polar accessor to modify the attributes of a Polar object (mutator)"""
pass

def __repr__(self):
"""Representation of a Polar object"""
pass

def getPolar(self):
"""Polar accessor that returns the attributes of a Polar object as a polar tuple (r, theta)"""
pass

def getCart(self):
"""Polar accessor that returns the attributes of a Polar object as a cartesian tuple (x, y)"""
pass

P1 = Polar(1.0, 180.0)
P2 = Polar(2.0, 90.0)

print("P1 = ", P1)
print("P2 = ", P2)

R2, T2 = P2.getPolar()
X2, Y2 = P2.getCart()

print(R2, T2)
print(X2, Y2)


Expected result:

P1 =  r = 1.000000, theta = 3.141593
P2 =  r = 2.000000, theta = 1.570796
2.0 90.0
1.22464679915e-16 2.0


Solution

### Step 3¶

class Polar(object):
def __init__(self, r, degree):
"""Polar constructor"""
pass

def putPolar(self, r, degree):
"""Polar accessor to modify the attributes of a Polar object (mutator)"""
pass

def __repr__(self):
"""Representation of a Polar object"""
pass

def getPolar(self):
"""Polar accessor that returns the attributes of a Polar object as a polar tuple (r, theta)"""
pass

def getCart(self):
"""Polar accessor that returns the attributes of a Polar object as a cartesian tuple (x, y)"""
pass

def putCart(self, x, y):
"""Polar accessor that modify the attributes of a Polar object by giving the corresponding cartesian coordinates"""
pass

P1 = Polar(1.0, 180.0)
P2 = Polar(2.0, 90.0)

print("P1 = ", P1)
print("P2 = ", P2)

R2, T2 = P2.getPolar()
X2, Y2 = P2.getCart()

print(R2, T2)
print(X2, Y2)

P1.putCart(0.0, -3.0)
P2.putCart(4.0, 0.0)

print("P1 = ", P1)
print("P2 = ", P2)


Expected result:

P1 =  r = 1.000000, theta = 3.141593
P2 =  r = 2.000000, theta = 1.570796
2.0 90.0
1.22464679915e-16 2.0
P1 =  r = 3.000000, theta = -1.570796
P2 =  r = 4.000000, theta = 0.000000


Solution

### Step 4¶

class Polar(object):
"""The Polar Class that describes point2D object either in polar coordinates (r, theta), with theta in degrees, or in cartesian coordinates (x, y)"""

def __init__(self, r, degree):
"""Polar constructor"""
pass

def __repr__(self):
"""Representation of a Polar object"""
pass

def __putPolar(self, (r, degree)):
pass

def __getPolar(self):
pass

def __getCart(self):
pass

def __putCart(self, (x, y) ):
pass

__cart_doc = """Cartesian attributes of a Polar object"""
__polar_doc = """Polar attributes of a Polar object"""
polar = property(__getPolar, __putPolar, doc=__polar_doc)
cart = property(__getCart, __putCart, doc=__cart_doc)

P1 = Polar(1.0, 180.0)
P2 = Polar(2.0, 90.0)

print("P1 = ", P1)
print("P2 = ", P2)

R2, T2 = P2.polar
X2, Y2 = P2.cart

print(R2, T2)
print(X2, Y2)

P1.cart = 0.0, -3.0
P2.cart = 4.0,  0.0

print("P1 = ", P1)
print("P2 = ", P2)


Expected result:

P1 =  r = 1.000000, theta = 3.141593
P2 =  r = 2.000000, theta = 1.570796
2.0 90.0
1.22464679915e-16 2.0
P1 =  r = 3.000000, theta = -1.570796
P2 =  r = 4.000000, theta = 0.000000


Solution

### Step 5¶

Add a static method to compute the distance between two Polar points. Transform the file into a module that can be called externally.

class Polar(object):
"""The Polar Class that describes point2D object either in polar coordinates (r, theta), with theta in degrees, or in cartesian coordinates (x, y)"""

def __init__(self, r, degree):
"""Polar constructor"""
pass

def __repr__(self):
"""Representation of a Polar object"""
pass

def __putPolar(self, (r, degree)):
pass

def __getPolar(self):
pass

def __getCart(self):
pass

def __putCart(self, (x, y) ):
pass

__cart_doc = """Cartesian attributes of a Polar object"""
__polar_doc = """Polar attributes of a Polar object"""
polar = property(__getPolar, __putPolar, doc=__polar_doc)
cart = property(__getCart, __putCart, doc=__cart_doc)

def distance(p1, p2):
"""Static method to compute the distance between two Polar object"""
pass
distance = staticmethod(distance)

if __name__ == "__main__":
P1 = Polar(1.0, 180.0)
P2 = Polar(2.0, 90.0)

print("P1 = ", P1)
print("P2 = ", P2)

R2, T2 = P2.polar
X2, Y2 = P2.cart

print(R2, T2)
print(X2, Y2)

P1.cart = 0.0, -3.0
P2.cart = 4.0,  0.0

print("P1 = ", P1)
print("P2 = ", P2)

print(Polar.distance(P1, P2))


Expected result:

P1 =  r = 1.000000, theta = 3.141593
P2 =  r = 2.000000, theta = 1.570796
2.0 90.0
1.22464679915e-16 2.0
P1 =  r = 3.000000, theta = -1.570796
P2 =  r = 4.000000, theta = 0.000000
Distance between P1 and P2 =  5.0


Solution

### Step 6¶

What about storing a Polar object using (internally) cartesian coordinates instead of polar coordinates. From a user point of view, it should change nothing. This is encapsulation :-).

A complete new implementation of a ''Polar'' module could be (with documentation and tests):

import math

__doc__ = """
This is the Polar module
"""
__author__ = "Gerald Monard"
__date__ = "2019-01-08"
__version__ = "0.1"

class Polar(object):
"""The Polar Class that describes point2D object either in polar coordinates (r, theta), with theta in degrees, or in cartesian coordinates (x, y)

>>> P1 = Polar(1.0, 180.0)
>>> P2 = Polar(2.0, 90.0)
>>> print "P1 = ", P1
P1 =  r = 1.000000, theta = 180.000000
>>> print "P2 = ", P2
P2 =  r = 2.000000, theta = 90.000000
>>> R2, T2 = P2.polar
>>> X2, Y2 = P2.cart
>>> print R2, T2
2.0 90.0
>>> print X2, Y2
1.22464679915e-16 2.0
>>> P1.cart = 0.0, -3.0
>>> P2.cart = 4.0,  0.0
>>> print "P1 = ", P1
P1 =  r = 3.000000, theta = -90.000000
>>> print "P2 = ", P2
P2 =  r = 4.000000, theta = 0.000000
>>> print Polar.distance(P1, P2)
5.0
"""

__slots__ = ["_x", "_y"]
def __init__(self, r, degree):
"""Polar constructor"""
self._x, self._y = Polar._polar2cart(r, degree)

def __repr__(self):
"""Representation of a Polar object"""
return "r = %f, theta = %f" % self.polar

def _getPolar(self):
return Polar._cart2polar(self._x, self._y)

def _putPolar(self, r, degree):
self._x, self._y = Polar._polar2cart(r, degree)

def _getCart(self):
return self._x, self._y

def _putCart(self, t):
self._x = t[0]
self._y = t[1]

_cart_doc = """Cartesian attributes of a Polar object"""
_polar_doc = """Polar attributes of a Polar object"""
polar = property(_getPolar, _putPolar, doc=_polar_doc)
cart = property(_getCart, _putCart, doc=_cart_doc)

def distance(p1, p2):
"""Static method to compute the distance between two Polar object"""
x1, y1 = p1.cart
x2, y2 = p2.cart
d = (x1-x2)**2 + (y1-y2)**2
return math.sqrt(d)
distance = staticmethod(distance)

# some functions to help conversions...
return degree/180.0*math.pi

def _cart2polar(x, y):
r = math.sqrt(x*x + y*y)
theta = math.atan2(y,x)
_cart2polar = staticmethod(_cart2polar)

def _polar2cart(r, degree):
x = r * math.cos(theta)
y = r * math.sin(theta)
return x, y
_polar2cart = staticmethod(_polar2cart)

if __name__ == "__main__":
import doctest
doctest.testmod()


Using the Polar module:

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #!/usr/bin/env python3 from Polar import Polar P1 = Polar(1.0, 180.0) P2 = Polar(2.0, 90.0) print "P1 = ", P1 print "P2 = ", P2 R2, T2 = P2.polar X2, Y2 = P2.cart print R2, T2 print X2, Y2 P1.cart = 0.0, -3.0 P2.cart = 4.0, 0.0 print "P1 = ", P1 print "P2 = ", P2 print "Distance between P1 and P2 = ", Polar.distance(P1, P2) 

Pydoc output:

Help on module Polar:

NAME
Polar - This is the Polar module

FILE
Polar.py

CLASSES
__builtin__.object
Polar

class Polar(__builtin__.object)
|  The Polar Class that describes point2D object either in polar coordinates (r, theta), with theta in degrees, or in cartesian coordinates (x, y)
|
|  >>> P1 = Polar(1.0, 180.0)
|  >>> P2 = Polar(2.0, 90.0)
|  >>> print "P1 = ", P1
|  P1 =  r = 1.000000, theta = 180.000000
|  >>> print "P2 = ", P2
|  P2 =  r = 2.000000, theta = 90.000000
|  >>> R2, T2 = P2.polar
|  >>> X2, Y2 = P2.cart
|  >>> print R2, T2
|  2.0 90.0
|  >>> print X2, Y2
|  1.22464679915e-16 2.0
|  >>> P1.cart = 0.0, -3.0
|  >>> P2.cart = 4.0,  0.0
|  >>> print "P1 = ", P1
|  P1 =  r = 3.000000, theta = -90.000000
|  >>> print "P2 = ", P2
|  P2 =  r = 4.000000, theta = 0.000000
|  >>> print Polar.distance(P1, P2)
|  5.0
|
|  Methods defined here:
|
|  __init__(self, r, degree)
|      Polar constructor
|
|  __repr__(self)
|      Representation of a Polar object
|
|  ----------------------------------------------------------------------
|  Static methods defined here:
|
|  distance(p1, p2)
|      Static method to compute the distance between two Polar object
|
|  ----------------------------------------------------------------------
|  Data descriptors defined here:
|
|  cart
|      Cartesian attributes of a Polar object
|
|  polar
|      Polar attributes of a Polar object

DATA
__author__ = 'Gerald Monard'
__date__ = '2019-01-08'
__version__ = '0.1'

VERSION
0.1

DATE
2019-01-08

AUTHOR
Gerald Monard


Solution