[Python] `NotImplementedError` gets triggered unexpectedly when tring to define an "abstract...

Discussão em 'Python' iniciado por Stack, Abril 26, 2025.

  1. Stack

    Stack Membro Participativo

    This question is related to a question about the implementation of class property in Python which I have asked yesterday. I received a working solution and wrote my classProp and ClassPropMeta as the solution suggests. However, when I want to use class property together with @abstractmethod, problem occurs.

    Below is a minimum example of the problem I have encountered. I defined my ClassPropMeta to extend ABCMeta because I want to avoid metaclass conflict and use both the features of abstract method decorator and class property to define an abstract class property, which means that all concrete subclasses of the class with abstract class property should have the property defined.

    In the example, A, B are abstract classes that should have a class property called X, while C is the concrete class where the value of X is defined.

    When running this code, I found that the NotImplementedError in the abstract method gets triggered unexpectedly. Further tracing the source by printing the cls value before the error is raised, I found that the value of cls points to class B. Then I set a breakpoint in the method and executed the command w in Pdb. The call stack output is attached after the code.

    From my analysis, it seems like that B.X has been called somewhere in the program. So can it be explained where does the B.X access take place?

    from abc import ABCMeta, abstractmethod
    from typing import Any


    class classProp[T, P](property):
    def __get__(self, instance: T, owner: type[T] = None) -> P:
    return self.fget(owner)


    class ClassPropMeta(ABCMeta):
    def __setattr__(cls, name: str, value: Any):
    if isinstance(desc := vars(cls).get(name), classProp) and not callable(
    desc.fset
    ):
    raise AttributeError("can't set attribute")
    return super().__setattr__(name, value)


    class A(metaclass=ClassPropMeta):
    __slots__ = ()

    @classProp
    @abstractmethod
    def X(cls):
    # breakpoint()
    raise NotImplementedError


    class B(A):
    ...
    # @classProp
    # def X(cls):
    # return 1


    class C(B):
    @classProp
    def X(cls):
    return 1


    print(C.X)
    # result: NotImplementedError gets triggered


    > d:\path\to\my\example.py(31)X()
    -> breakpoint()
    (Pdb) w
    d:\path\to\my\example.py(35)<module>()
    -> class B(A):
    <frozen abc>(107)__new__()
    d:\path\to\my\example.py(13)__get__()
    -> return self.fget(owner)
    > d:\path\to\my\example.py(31)X()
    -> breakpoint()

    Continue reading...

Compartilhe esta Página