Skip to content

Adressing the object.__eq__ dilemma. #15345

@randolf-scholz

Description

@randolf-scholz

The Dilemma

# current annotation in typeshed
class object:
    def __eq__(self, value: object, /) -> bool: ...

This is too strict, because everything subclasses object and some classes may to wish to:

  1. Narrow the range of allowed objects.
  2. Use a return type other than bool (e.g. numpy array element-wise comparison, symbolic computation, etc.)

On the other hand, many APIs (incorrectly) assume that a == b always return a bool, so changing the return type away from bool can lead to problems.

Solving the Dilemma

Satisfying (1) is easy enough by changing value: object to value: Any. (one could maybe explore using Never also)

Satisfying (2) can be achieved in several ways, specifically I tested: (a) -> object, (b) -> Any and (c) -> Any | bool

In particular, for (c) the primer actually looks really good. We have ~50 fixed Unused "type: ignore" comment errors, and 16 suprious [override] errors eliminated, without any new errors.


References

Appendix: How python's a==b works internally

This cannot be properly annotated with the current type system, so all type checkers need to special case it.

def eq(left, right):
    left_type = type(left)
    right_type = type(right)

    # if RHS is proper subtype of LHS, try RHS's equality method
    if left_type != right_type and issubclass(right_type, left_type):
        result = right.__eq__(left)
        if result is not NotImplemented:
            return result

    # try LHS's equality method
    result = left.__eq__(right)
    if result is not NotImplemented:
        return result

    # try RHS's equality method
    result = right.__eq__(left)
    if result is not NotImplemented:
        return result
    
    return False  # fallback if all methods return NotImplemented

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions