[Python] Exception thrown in python magic method is lost on the way

Discussão em 'Python' iniciado por Stack, Junho 20, 2025.

  1. Stack

    Stack Membro Participativo

    For a project, I want to prevent the use of certain methods in an overriding class. As this happens rather frequently, I am using a metaclass to block many methods at once (how and why is not within the scope of this question).

    This is done by replacing the methods I want to block by a data descriptor, which throws an exception. Using a data descriptor is helpful, as it comes first in the attribute lookup, but is not of special relevance other than that.

    This approach is also used for magic methods which override operators (e.g. the == operator). When calling the magic method __eq__ directly, the exception is raised as expected. When indirectly calling it using ==, it is also raised, but apparently caught somewhere on the way.

    • Why is this the case? It seems there is a catch-all somewhere along the way (I tested different exception types), but I do not understand why this is beneficial for the language behaviour. Is there a reason?
    • Is there a way to change my approach, such that both uses throw an exception?

    MWE:

    from typing import override

    class ErrorDescriptor:
    def __get__(self, obj: object, objtype: object = None):
    print("Exception incoming")
    raise RuntimeError()

    def __set__(self, obj: object, objtype: object = None): ...

    class Meta(type):
    def __new__(cls, name: str, bases: tuple[type, ...], cls_dict: dict[str, object]):
    cls_dict["__eq__"] = ErrorDescriptor()
    return super().__new__(cls, name, bases, cls_dict)

    class Foo:
    @override
    def __eq__(self, other: object):
    return True

    class Bar(Foo, metaclass=Meta):
    pass

    print(Foo() == 0) # True
    print(Bar() == 0) # Exception incoming\n False
    # ^^^^^ ?!
    print(Bar().__eq__(0)) # Exception incoming\n raises RuntimeError

    Continue reading...

Compartilhe esta Página