For an introduction to OOP ideas and paradigms, check the slides and see the 3 simple examples below:
1. Constructor (__init__)
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
f1 = Fraction(2, 3)
f2 = Fraction(1, 5)
print(f1.num, f1.den)
print(f2.num, f2.den)
2. Converting to strings
Defining a toString() method
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
def toString(self):
return str(self.num) + "/" + str(self.den)
f1 = Fraction(2, 3)
f2 = Fraction(1, 5)
print(f1.toString())
print(f2.toString())
The problem
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
def toString(self):
return "%d/%d" % (self.num, self.den)
f1 = Fraction(2, 3)
f2 = Fraction(1, 5)
print(f1.toString()) # prints 2/3
print(f2.toString()) # prints 1/5
# What about print(f1) or print(f2)?
print(f1) # prints <__main__.Fraction object at 0x10611db38> (yuck!)
print(f2) # prints <__main__.Fraction object at 0x10611dba8> (yuck!)
The partial solution: __str__
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
def __str__(self):
return "%d/%d" % (self.num, self.den)
f1 = Fraction(2, 3)
f2 = Fraction(1, 5)
print(f1) # prints 2/3
print(f2) # prints 1/5
# What about adding a fraction object to a list and printing the list?
L = []
L.append(f1)
L.append(f2)
print(L) # prints [<__main__.Fraction object at 0x106f68ba8>,
# <__main__.Fraction object at 0x106f68be0>] (yuck!)
The better solution: __repr__
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
def __repr__(self):
return "%d/%d" % (self.num, self.den)
f1 = Fraction(2, 3)
f2 = Fraction(1, 5)
# What about print(f1) or print(f2)?
print(f1) # prints 2/3
print(f2) # prints 1/5
# What about adding a fraction object to a list and printing the list?
L = []
L.append(f1)
L.append(f2)
print(L) # prints [2/3, 1/5]
3. Equality Testing
Comparing objects: defining our own method
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
def equal(self, other):
return self.num == other.num and self.den == other.den
f1 = Fraction(10, 2)
f2 = Fraction(10, 2)
print(f1.equal(f2)) # True
# What about using == ?
print(f1 == f2) # False!
The partial solution: __eq__
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
def __eq__(self, other):
return self.num == other.num and self.den == other.den
f1 = Fraction(10, 5)
f2 = Fraction(10, 5)
print(f1 == f2) # True
# Can we compare objects from our own class to objects of other classes?
print(f1 == 2) # Crashes!
A better solution
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
def __eq__(self, other):
if (isinstance(other, int)):
return self.num/self.den == other
elif (isinstance(other, Fraction)):
return self.num == other.num and self.den == other.den
return False
f1 = Fraction(10, 5)
f2 = Fraction(10, 5)
print(f1 == f2) # True
print(f1 == 2) # True
4. Multiplying two fractions
The problem
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
f1 = Fraction(1, 4)
f2 = Fraction(2, 4)
print(f1 * f2) # Crashes
Using: __mul__
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
def __repr__(self):
return "%d/%d" % (self.num, self.den)
def __mul__(self, other):
num = self.num*other.num
den = self.den*other.den
return Fraction(num, den)
f1 = Fraction(1, 4)
f2 = Fraction(2, 4)
print(f1*f2) # prints 2/16
5. Using in Sets (__hash__ and __eq__)
The problem
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
s = set()
f1 = Fraction(1, 4)
f2 = Fraction(1, 4)
s.add(f1)
print(f1 in s) # True
print(f2 in s) # False (but 1/4 should be in the set!)
The solution: __hash__ and __eq__
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
def __eq__(self, other):
if (isinstance(other, int)):
return self.num/self.den == other
elif (isinstance(other, Fraction)):
return self.num == other.num and self.den == other.den
return False
def __hash__(self):
return hash((self.num, self.den))
s = set()
f1 = Fraction(1, 4)
f2 = Fraction(1, 4)
s.add(f1)
print(f1 in s) # True
print(f2 in s) # True
6. Using in Dictionaries (__hash__ and __eq__)
The problem
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
d = dict()
f1 = Fraction(1, 4)
f2 = Fraction(1, 4)
d[f1] = 0.4
print(d[f2]) # crashes: key-error! (But 1/4 should be in the dictionary)
The solution (same as sets):
class Fraction(object):
def __init__(self, num, den):
self.num = num
self.den = den
def __eq__(self, other):
if (isinstance(other, int)):
return self.num/self.den == other
elif (isinstance(other, Fraction)):
return self.num == other.num and self.den == other.den
return False
def __hash__(self):
return hash((self.num, self.den))
d = dict()
f1 = Fraction(1, 4)
f2 = Fraction(1, 4)
d[f1] = 0.4
print(d[f2]) # prints 0.4
6. The full Fraction example
The solution (same as sets):
# Very simple, far-from-fully implemented Fraction class
# to demonstrate the OOP ideas from above.
# Note that Python actually has a full Fraction class that
# you would use instead (from fractions import Fraction),
# so this is purely for demonstrational purposes.
def gcd(x, y):
if (y == 0): return x
else: return gcd(y, x%y)
class Fraction(object):
def __init__(self, num, den):
# Partial implementation -- does not deal with 0 or negatives, etc
g = gcd(num, den)
self.num = num // g
self.den = den // g
def __repr__(self):
return '%d/%d' % (self.num, self.den)
def __eq__(self, other):
if (isinstance(other, int)):
return self.num/self.den == other
elif (isinstance(other, Fraction)):
return self.num == other.num and self.den == other.den
return False
def __mul__(self, other):
if (isinstance(other, int)):
return Fraction(self.num * other, self.den)
else:
return Fraction(self.num * other.num, self.den * other.den)
def __hash__(self):
return hash((self.num, self.den))
def testFractionClass():
print('Testing Fraction class...', end='')
assert(str(Fraction(2, 3)) == '2/3')
assert(str([Fraction(2, 3)]) == '[2/3]')
assert(Fraction(2,3) == Fraction(2,3))
assert(Fraction(2,3) != Fraction(2,5))
assert(Fraction(2,3) != "Don't crash here!")
assert(Fraction(2,3) * (Fraction(3,4)) == Fraction(1,2))
assert(Fraction(2,3) * 5 == Fraction(10,3))
s = set()
assert(Fraction(1, 2) not in s)
s.add(Fraction(1, 2))
assert(Fraction(1, 2) in s)
s.remove(Fraction(1, 2))
assert(Fraction(1, 2) not in s)
print('Passed.')
if (__name__ == '__main__'):
testFractionClass()