Zhihar
Zhihar

Reputation: 1428

python: overload operator > with different types

tell me how to overload the operator > (lt) or < (gt) etc so that it can work with different types (especially with 0)

for example:

class CRational(object):

    def __init__(self, a = 0, b = 1):
        self.a = a
        self.b = b
        
    def __neg__(self):
        return CRational(-self.a, self.b)

    def __add__(self, other):
        return CRational(self.a * other.b + other.a * self.b, self.b * other.b)

    def __sub__(self, other):
        return CRational(self.a * other.b - other.a * self.b, self.b * other.b)

    def __mul__(self, other):
        return CRational(self.a * other.a, self.b * other.b)

    def __truediv__(self, other):
        return CRational(self.a * other.b, self.b * other.a)

    def __eq__(self, other):
        return self.a * other.b == other.a * self.b

    def __ne__(self, other):
        return not self.__eq__(other)

    def __lt__(self, other):
        return self.a * other.b < other.a * self.b

    def __le__(self, other):
        return self.a * other.b <= other.a * self.b

    def __gt__(self, other):
        return self.a * other.b > other.a * self.b

    def __ge__(self, other):
        return self.a * other.b >= other.a * self.b

error output:

File "lessons/python/square_eq.py", line 66, in __gt __ return self.a * other.b > other.a * self.b AttributeError: 'int' object has no attribute 'b'

in code:

s_a = "" if a > 0 else "-"

how do you fix it?

s_a = "" if a > CRational(0) else "-"

the method described above helps, but it is not beautiful :)

Upvotes: 2

Views: 868

Answers (3)

MichaelFour
MichaelFour

Reputation: 21

Sounds like you're wanting to test for what kind of object you are working with. Maybe something like:

import numbers

def __gt__(self, other):
    if isinstance(other, type(self)):
        return self.a * other.b > other.a * self.b
    elif isinstance(other, numbers.Number):
        return self.a > other
    else:
        err_str = "Unknown type in comparison with %s object: %s" % (type(self).__name__, type(other).__name__)
        raise(TypeError(err_str))

Here, type(self) is a generic way of getting the CRational class. That way you don't have to modify the class's code if you simply change the name later.

isinstance checks to see if a given object is of the given type, or a child type. Python documentation.

I made up the numeric case, because I don't know how you'd want to define that.

Upvotes: 2

Riccardo Bucco
Riccardo Bucco

Reputation: 15384

If you want to compare a CRational object with an int then your __gt__ method should works with integers too. I.e., if other is an integer, you clearly can't do something like other.b. Here is a possible solution:

class CRational:
    def __init__(self, a = 0, b = 1):
        self.a = a
        self.b = b
    def __gt__(self, other):
        if isinstance(other, CRational):
            return self.a * other.b > other.a * self.b
        elif isinstance(other, int):
            # Compare self (a CRational object) with other (an int)
            # TODO
        else:
            raise NotImplemented()

Now you can do something like this:

a = CRational()
if a > 3:
    ...

Be careful though! Even if you implement correctly all the methods, you still can't do 3 > a. Order is important!! 3 > a would call the __gt__ method of the int class. You can only do a > 3, a < 3, a >= 3 etc.

Upvotes: 4

Algebra8
Algebra8

Reputation: 1385

With regards to your error output: you are getting the error because your "other" is an int and CRational.__gt__ is trying to access an attribute that it does not have a b:

def __gt__(self, other):  # passing in an int here
        return self.a * other.b > other.a * self.b

With regards to your code example, assuming a is another CRational object, then a > 0 will cause the AttributeError you are seeing above and the only way to fix it is by comparing it with either another CRational object or some other object that has attribues a and b.

Upvotes: 2

Related Questions