Python Forum

Full Version: __eq__ method related problem
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
To keep things brief. Suppose I have a simple Car class with only a single attribute - model:

class Car(object):
    def __init__(self, model):
        self.model = model
    def __eq__(self, other):
        return self.model==other.model
Then I create a Car object:

my_car = Car('Mercedes')
Now suppose I create a simple list object:

my_list = [1, 3.14, 1, 0 , 0, 1, 'some_string', my_car]
Now, I want to count the number of occurrences of 1. This should be 3. However I get the error:

Error:
AttributeError: 'int' object has no attribute 'model
I understand what is going on. The count function behind the scenes makes use of __eq__ function of Car which I defined and since the int object does not have the model attribute, it issues an error. My question is, what is the point of having such an implementation of __eq__ function then? Seems like if any of the object in the list has the __eq__ method overriden, the count method of the list becomes useless.

Wouldn't it be better the count method to be designed in a way that it calls the __eq__ function of the (incoming) int object rather than of those in the list?
Write a better __eq__().
def __eq__(self, other):
    return isinstance(other, self.__class__) and other.model == self.model
Edit: I saw it too late. This answer is only related to comparison. tl;dr: Do not compare apples with bananas :-)

For comparison, you need the methods __lt__, __le__, __gt__, __ge__

How can you compare "BMW", "Mercedes", "Audi", "Volkswagen" with a float or integer? How to sort a list with these elements?

Example how you could do it, but shouldn't do it.
from functools import total_ordering


@total_ordering
class Car:
    def __init__(self, model):
        self.model = model

    def __gt__(self, other):
        """
        Always False until you find a solution to compare cars with numbers.
        """
        return False

    def __repr__(self):
        return f'{self.__class__.__name__}(model="{self.model}")'


class Bike(Car):
    pass


my_car = Car("Mercedes")
my_bike = Bike("Citybike")

# removed the str, becuase it does not make any sense to compare text to a number
my_list = [1, 3.14, 1, 0, 0, 1, my_car, my_bike]
my_list.sort()
print(my_list)
Output:
[Bike(model="Citybike"), Car(model="Mercedes"), 0, 0, 1, 1, 1, 3.14]
Deanhistad's idea looks like the way to go, however it is seldom a good idea to define an __eq__() method in a class in Python. I think the real question is why do you want to define this method? What's the use case for this? Among other issues, you won't be able to insert Car instances into sets or use them as dictionary keys.
(Mar-08-2025, 02:21 PM)Gribouillis Wrote: [ -> ]Deanhistad's idea looks like the way to go, however it is seldom a good idea to define an __eq__() method in a class in Python. I think the real question is why do you want to define this method? What's the use case for this? Among other issues, you won't be able to insert Car instances into sets or use them as dictionary keys.

The use case is to make a comparison based on your defined criteria.

c1 = Car('Mercedes')
c2 = Car('BMW')

print(c1 == c2)
In addition I might have a list of various objects.
(Mar-08-2025, 07:01 PM)Tsotne Wrote: [ -> ]The use case is to make a comparison based on your defined criteria.

c1 = Car('Mercedes')
c2 = Car('BMW')

print(c1 == c2)
In addition I might have a list of various objects.
If you need to compare cars based on the model, you can simply write the more explicit
print(c1.model == c2.model)
Also if you don't defineCar.__eq__(), the code thelist.count(1) will work because equality defaults to object identity.
Thank you all. This was a very simplified extract from a more complex implementation. However, I got the useful insights.