Matt Swain
Matt Swain

Reputation: 3887

Best way to implement multiple types of equality checks in python

Say I have a Person class, with first, middle and last name attributes. I would like to be able to perform two different types of equality checks on Person objects:

I have been toying with the idea of using __eq__ and __ne__ separately for this:

Person('g', '', 'bluth') == Person('george', 'oscar', 'bluth')  # False
Person('g', '', 'bluth') != Person('george', 'oscar', 'bluth')  # False

It seems like a neat solution, but having != not always return the opposite of == makes me nervous though. Is it considered bad practice? Should I just steer clear of using the operators and just use a method like consistent(self, other)?

Example implementation:

class Person(object):
    def __init__(self, first, middle, last):
        self.first = first
        self.middle = middle
        self.last = last
    def __eq__(self, other):
        if type(other) is type(self):
            return self.__dict__ == other.__dict__
        return NotImplemented
    def __ne__(self, other):
        if type(other) is type(self):
            return not (self._compatible(self.first, other.first) and 
                        self._compatible(self.middle, other.middle) and 
                        self._compatible(self.last, other.last))
        return NotImplemented
    def _compatible(self, s, o):
        if s and o:
            if s == o or (len(s) == 1 and s == o[0]) or (len(o) == 1 and o == s[0]):
                return True
            return False
        return True

Upvotes: 0

Views: 139

Answers (1)

morningstar
morningstar

Reputation: 9132

Principle of least astonishment: make the inexact match be a named method, not an overloaded operator. Overloading == for exact match is okay, but overloading operators with semantics other than the obvious is likely to cause confusion. Is it terribly hard to type a few more characters and write Person("G. Bluth").could_be(Person("George Oscar Bluth"))?

Upvotes: 5

Related Questions