Why does defining the argument types for __eq__ throw a MyPy type error?

Your reading of the docs is right -- you need to give the method (__eq__) the same signature as it has already in the base class (object), or else a more permissive one.

The reason for that is that because your MyObject is a subtype of object, a MyObject could be passed anywhere that expects an object... which means that that code could compare it with any other object, and there's no legitimate way for the type checker to complain. So, to reflect that, your __eq__ has to be written to expect any object.

What you can do is right up front in the method's body, check the type and return (or raise an exception):

if not isinstance(other, MyObject):
  return False

Then as those docs say, Mypy is smart enough that after that check, it will know that other is a MyObject and treat it accordingly.


== is supposed to take arbitrary other objects, not just objects of your type. If it doesn't recognize the other object, it should return NotImplemented:

class MyObject(object):
    def __init__(self, value: int=5) -> None:
        self.value = value

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, MyObject):
            return NotImplemented
        return self.value == other.value

NotImplemented isn't an instance of bool, but mypy seems to have a weird special case for that. It wants the return annotation to be bool, and it doesn't complain about the return NotImplemented line.

Also, if you need to refer to MyObject for type hints inside its own body, you need to use a string, 'MyObject' instead of MyObject. MyObject doesn't exist yet.