pythonrational-numbers

Multiplying Fractions and Integers in Python


I'm trying to build a rational numbers class that will perform various arithmetic functions based on input values without using the fractions module. When I'm using two different fractions the code works fine, but as soon as I try to use an integer I'm getting errors in earlier class functions and am unsure why. What I'm trying to implement at this point is, again, adding an integer to a rational number (e.g., print Rational(1,2) * 3).

I've included the code that I have thus far below - the problematic operation is __radd__, though when this is included in my code I receive an attribute error for __add__ (this error does not show up until this new operation is included). I'm guessing the problem comes from still having the 2nd __radd__ parameter as other (assuming a different case of the Rational class?), but am unsure how to proceed.

Edit: I'm using Python 2.7. The error from a sample run is included below the code.

def gcd(a, b):
    if b == 0:
        return a
    else:
        return gcd(b, a%b)
class Rational:
    def __init__(self, nom, denom):
        if denom == 0:
            raise ZeroDivisionError, ("Cannot divide by zero!")
        else:
            self.reduce = gcd(nom, denom)
            self.nom = nom / self.reduce
            self.denom = denom / self.reduce
    def __add__ (self, other):
        return Rational(self.nom*other.denom+other.nom*self.denom, self.denom*other.denom)        
    def __sub__ (self, other):
        return Rational(self.nom * other.denom - other.nom * self.denom,self.denom * other.denom)    
    def __mul__ (self, other):
        return Rational(self.nom * other.nom, self.denom * other.denom)
    def __div__ (self, other):
        return Rational(self.nom * other.denom, self.denom * other.nom)
    def __radd__ (self, other):
        return Rational(self.nom*1+other*self.denom, self.denom*1) 
    def __str__ (self):
        return str(self.nom) + "/" + str(self.denom)

Sample error

print Rational(1,2) + 1

AttributeError                            Traceback (most recent call last)
<ipython-input-201-1ccb1fc0dfef> in <module>()
----> 1 print Rational(1,2) + 1

C:\Users\turk\Documents\EV_HW6_P2.py in __add__(self, other)
     13             self.denom = denom / self.reduce
     14     def __add__ (self, other):
---> 15         return Rational(self.nom*other.denom+other.nom*self.denom, self.denom*other.denom)
     16     def __sub__ (self, other):
     17         return Rational(self.nom * other.denom - other.nom * self.denom,self.denom * other.denom)

AttributeError: 'int' object has no attribute 'denom' 

Solution

  • When Python see Rational on left side of + then it uses __and__ but if there is no Rational on left size but it is on right side then Python use __radd__. (r in name __radd__ means right)

    In __add__ you use other.nom and other.denom which doesn't exists in int so Rational(1,2) + 1 doesn't work.

    1 + Rational(1,2) works because in __radd__ you use other instead of other.nom and other. denom

    You can use isinstance(other, int) to recognize int and make different calculation in __add__ and it will works with Rational+int and Rational+Rational

    def __add__ (self, other):
        if isinstance(other, int):
            # Rational + int
            return Rational(self.nom*1+other*self.denom, self.denom*1) 
        else:
            # Rational + Rational
            return Rational(self.nom*other.denom+other.nom*self.denom, self.denom*other.denom)        
    
    # ----
    
    print(Rational(1,2) + 1)
    print(Rational(1,2) + Rational(1,2))