Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generalized __eq__() method in Python

I'd like to create a generalized __eq__() method for the following Class. Basically I'd like to be able to add another property (nick) without having to change __eq__()

I imagine I can do this somehow by iterating over dir() but I wonder if there is a way to create a comprehension that just delivers the properties.

 class Person:
     def __init__(self, first, last):
         self.first=first
         self.last=last

     @property
     def first(self):
         assert(self._first != None)
         return self._first
     @first.setter
     def first(self,fn):
         assert(isinstance(fn,str))
         self._first=fn

     @property
     def last(self):
         assert(self._last != None)
         return self._last
     @last.setter
     def last(self,ln):
         assert(isinstance(ln,str))
         self._last=ln
     @property
     def full(self):
         return f'{self.first} {self.last}'

     def __eq__(self, other):
         return self.first==other.first and self.last==other.last

 p = Person('Raymond', 'Salemi')
 p2= Person('Ray', 'Salemi')
like image 507
Ray Salemi Avatar asked Mar 09 '18 15:03

Ray Salemi


People also ask

What is __ eq __ method in Python?

Summary. Implement the Python __eq__ method to define the equality logic for comparing two objects using the equal operator ( == )

What is __ class __ in Python?

__class__ is an attribute on the object that refers to the class from which the object was created. a. __class__ # Output: <class 'int'> b. __class__ # Output: <class 'float'> After simple data types, let's now understand the type function and __class__ attribute with the help of a user-defined class, Human .

What does __ add __ do in Python?

Python __add__() method adds two objects and returns a new object as a resultant object in Python. The below example returns a new object, Python3.

What is __ INT __ in Python?

The __int__ method is called to implement the built-in int function. The __index__ method implements type conversion to an int when the object is used in a slice expression and the built-in hex , oct , and bin functions.


2 Answers

You could use __dict__ to check if everything is the same, which scales for all attributes:

If the objects are not matching types, I simply return False.

class Person:
    def __init__(self, first, last, nick):
        self.first = first
        self.last = last
        self.nick = nick

    def __eq__(self, other):
        return self.__dict__ == other.__dict__  if type(self) == type(other) else False

>>> p = Person('Ray', 'Salemi', 'Ray')
>>> p2= Person('Ray', 'Salemi', 'Ray')
>>> p3 = Person('Jared', 'Salemi', 'Jarbear')

>>> p == p2
True
>>> p3 == p2
False
>>> p == 1
False
like image 75
user3483203 Avatar answered Oct 12 '22 11:10

user3483203


You can get all the properties of a Class with a construct like this:

from itertools import chain
@classmethod
def _properties(cls):
    type_dict = dict(chain.from_iterable(typ.__dict__.items() for typ in reversed(cls.mro())))
    return {k for k, v in type_dict.items() if 'property' in str(v)}

The __eq__ would become something like this:

def __eq__(self, other):
    properties = self._properties() & other._properties()
    if other._properties() > properties and self._properties() > properties:
        # types are not comparable
        return False
    try:
        return all(getattr(self, prop) == getattr(other, prop) for prop in properties)
    except AttributeError:
        return False

The reason to work with the reversed(cls.mro()) is so something like this also works:

class Worker(Person):
    @property
    def wage(self):
        return 0

p4 = Worker('Raymond', 'Salemi')

print(p4 == p3)
True
like image 31
Maarten Fabré Avatar answered Oct 12 '22 12:10

Maarten Fabré