Search code examples
pythonclassfractionsunary-operator

How to perform unary operations on a class in Python?


I have written a code where I have defined a class Fraction. Throughout the code, all binary operations such as +, -, /, * can be performed. Now I would also like to be able to perform unary operations for the class Fraction such as abs() etc. However, this does not work at the moment, when performing for example the unary operation abs() I get a TypeError: bad operand type for abs (): 'Fraction'. Below is part of the code that deals purely with fraction subtraction, it is representative for the entire code:

def gcd(denominator, numerator):
    if numerator == 0:
        return denominator
    else:
        return gcd(numerator, (denominator % numerator))

class Fraction:
    
    def __init__(self,numerator = 0, denominator = 1):

        self.numerator = int(numerator / gcd(abs(denominator),abs(numerator) ))
        self.denominator = int(denominator / gcd(abs(denominator),abs(numerator) ))
        if self.denominator < 0:
            self.denominator = abs(self.denominator)
            self.numerator = -1*self.numerator
        elif self.denominator == 0:
            raise ZeroDivisionError
        
    def __str__(self):
        if self.denominator == 1:
            return str(self.numerator)
        else:
            return str(self.numerator) + "/" + str(self.denominator)
    
    def __neg__(self):
        return Fraction(-self.numerator, self.denominator)
    
    def __rsub__(self,other):
        return self.__sub__(other)

    def __sub__(self,other):
        if type(other) == int:
            other = Fraction(other,1)
            return self.sub(other)
        else:
            
            return self.sub(other)
    
    def sub(self,other):
        result = Fraction()
        
        result.numerator = other.denominator * self.numerator - self.denominator * other.numerator
        result.denominator = other.denominator * self.denominator
        
        multiple = gcd(result.denominator,result.numerator)
        
        result.numerator = int(result.numerator / multiple)
        result.denominator = int(result.denominator / multiple)
        
        if result.denominator < 0:
            result.denominator = abs(result.denominator)
            result.numerator = 0 - result.numerator
            return result    
        
        else:
            return result
        
        return result


p = Fraction(2,3)
q = Fraction(4,5)

r = (p - q)

What I would like is that when I give the statement print(abs(r)) the output is the fraction in absolute value. So in the example where p = Fraction(2,3), q = Fraction(4,5) and r = (p - q). Then the statement print(r) gives the output -2/15 and the statement print(abs(r)) gives the output 2/15. Or that for example print(float(r)) gives the output -0.133333333. However, I keep getting the previously mentioned TypeError.

I've been looking for a while, but so far I haven't been able to find a solution, do you know how I can fix this?

Thanks in advance!


Solution

  • As already mentioned in the comment implement __abs__ and __float__.

    Add this to your class:

        def __abs__(self):
            return Fraction(abs(self.numerator), abs(self.denominator))
    
        def __float__(self):
            return self.numerator / self.denominator
    

    Maybe

        def __abs__(self):
            return Fraction(abs(self.numerator), self.denominator)
    

    would be already enough, when your denominator is always positive.

    >>> p = Fraction(2, 3)
    >>> q = Fraction(4, 5)
    >>> r = p - q
    >>> print(r)
    -2/15
    >>> print(abs(r))
    2/15
    >>> print(float(r))
    -0.13333333333333333