0

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' 
turkadactyl
  • 3
  • 1
  • 3
  • Please show the full error traceback, and the call that leads to that error. You may also want to include whether you're using Python 2, Python 3 or have `from __future__ import division`, as that will make quite a difference here (or perhaps just use `//` instead of `/`, assuming you want integer divisions). –  Oct 31 '16 at 02:44
  • Added, thanks for the suggestions. – turkadactyl Oct 31 '16 at 02:53
  • `Rational(1,2) + 1` uses `__add__` , `1 + Rational(1,2)` uses `__radd__` – furas Oct 31 '16 at 02:55
  • Furas: You're right - when I make that change to the call it works perfectly. Can you explain why that difference matters here? – turkadactyl Oct 31 '16 at 02:57
  • `r` means `right` so if `Rational` is on right size of `+` then Python use `__radd__`. In `__radd__` you doesn't use `other.nom` and `other.denom` but you add `int` to `Rational` so you get correct result. – furas Oct 31 '16 at 02:59
  • in `__add__` use `isinstance(other, int)` to recognize `int` and do different calculation. – furas Oct 31 '16 at 03:00

1 Answers1

1

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))
furas
  • 134,197
  • 12
  • 106
  • 148