2. Object Mutability

We can change the state of a mutable object by making an assignment to one of its instance variables. For example, we could change the numerator of the fraction by assigning a new value to self.num. Likewise, we could do the same thing for self.den.

One place where this type of modification makes sense is when we place a fraction in lowest terms. Lowest terms simply means that the numerator and denominator do not share any common factors. For example, 12/16 is a fraction but it is not in lowest terms since 2 can divide into both 12 and 16. In this case, we call 2 a common divisor. If we divide the numerator and the denominator by a common divisor, we get an equivalent fraction. If we divide by the greatest common divisor, we will get the lowest terms representation. In this case 4 would be the greatest common divisor and the lowest terms representation would be 3/4.

There is a very nice iterative method for computing the greatest common divisor of two integers. Try to run the function on a number of different examples.

 
1
def find_gcd(numerator, denominator):
2
    while numerator % denominator != 0:
3
        old_num = numerator
4
        old_den = denominator
5
6
        numerator = old_den
7
        denominator = old_num % old_den
8
9
    return denominator
10
11
print(find_gcd(12, 16))
12
Output

Now that we have a function that can help us with finding the greatest common divisor, we can use that to implement a fraction method called simplify. We will ask the fraction “to put itself in lowest terms”.

The simplify method will pass the numerator and the denominator to the find_gcd function to find the greatest common divisor. It will then modify itself by dividing its num and its den by that value.

36
 
1
def find_gcd(numerator, denominator):
2
    while numerator % denominator != 0:
3
        old_num = numerator
4
        old_den = denominator
5
6
        numerator = old_den
7
        denominator = old_num % old_den
8
9
    return denominator
10
11
class Fraction:
12
13
    def __init__(self, top, bottom):
14
15
        self.num = top        # the numerator is on top
16
        self.den = bottom     # the denominator is on the bottom
17
18
    def __repr__(self):
19
        return str(self.num) + "/" + str(self.den)
20
21
    def simplify(self):
22
        common = find_gcd(self.num, self.den)
23
24
        self.num = self.num // common
25
        self.den = self.den // common
26
27
def main():
28
    myfraction = Fraction(12, 16)
29
30
    print(myfraction)
31
    myfraction.simplify()
32
    print(myfraction)
33
34
if __name__ == "__main__":
35
    main()
36
Output

There are two important things to note about this implementation. First, the find_gcd function is not a method of the Fraction class. It does not belong to Fraction. Instead it is a function that is used by Fraction to assist in a task that needs to be performed. This type of function is often called a helper function. Second, the simplify method does not return anything. Its job is to modify the object itself. This type of method is known as a mutator method because it mutates or changes the internal state of the object.