How to overload an __eq__ function that gets an object of the self class

345 Views Asked by At

What i'm trying is to overload this function that is in Posicion class using singledispatch and trying to follow the OOP:

def __eq__(self, other):
    if isinstance(other, Posicion):
        return other.get_posicion() == self.get_posicion()

    elif type(other) == tuple:
        assert len(other) == 2, "La tupla pasada por parámetro debe constar de dos elementos"
        self.verificar_formato(other[0], other[1])

        return (other[0].upper(), other[1]) == self.get_posicion()

I tried to apply singledispatch from functools library but i ran into the same errors as this question: python3: singledispatch in class, how to dispatch self type. because i'm trying to dispatch the self type. So i tryied

class _Posicion:
    def __init__(self, y, x):
    pass


class Posicion(_Posicion):
    def __init__(self, y, x):
        super()
        self.x = x
        self.y = y.upper()

    def get_posicion(self):
        return self.y, self.x

    @singledispatch
    def __eq__(self, other):
        raise NotImplementedError("Everything bad")
            

    @__eq__.register(_Posicion)
    def _(self, other):
        return other.get_posicion() == self.get_posicion()
    
    @__eq__.register(tuple)
    def _(self, other):
        assert len(other) == 2, "La tupla pasada por parametro debe constar de dos elementos"
        self.verificar_formato(other[0], other[1])

        return (other[0].upper(), other[1]) == self.get_posicion()


if __name__ == "__main__":
    Posicion('a', 1) == ('a', 1)
    

But it always enter in the @__eq__.register(_Posicion) and if i deleted it always enter int the def __eq__(self, other):

I apologize, again, for the possibly bad wording of this question and thanks in advance for the help. If there is any other information that I should add, please let me know.

1

There are 1 best solutions below

0
On BEST ANSWER

I would use a mix of duck-typing and single-dispatch.

@singledispatchmethod
def __eq__(self, other):
    try:
        f = other.get_posicion
    except AttributeError:
        return (self is other) or NotImplemented

    return self.get_posicion() == f()

@__eq__.register(tuple)
def _(self, other):
    assert len(other) == 2, "La tupla pasada por parámetro debe constar de dos elementos"
    self.verificar_formato(other[0], other[1])

    return (other[0].upper(), other[1]) == self.get_posicion()

This slightly weakens what you were trying: instead of insisting on comparing two Posicion instances, we allow comparing a Posicion to anything implementing a callable get_posicion attribute. If it fails, just compare based on object identity, otherwise call both object's method and compare the results.

The only explicit type we check for is tuple, avoiding the need to have a true reference to Posicion inside the class definition itself. (Though if you like, you can safely check isinstance(other, Posicion) inside the definition of __eq__; it's just as an argument to singledispatchmethod that Posicion is not yet defined.)