如何实现可与@abstractmethod链式使用的@classproperty装饰器
可与@abstractmethod链式使用的classproperty实现方案
核心修改点
- 修正
__isabstractmethod__属性实现:透传被装饰方法的__isabstractmethod__标记,让ABC元类可以正确识别抽象类属性,原生触发实例化时的类型校验 - 新增访问校验逻辑:在
__get__方法中判断如果是未实现的抽象类属性,直接抛出符合原生@abstractmethod格式的TypeError - 装饰器顺序要求:
@classproperty必须放在@abstractmethod外层,保证抽象标记可以正确透传
完整实现代码
from abc import ABC, abstractmethod class classproperty(property): """ 类属性装饰器,支持与@abstractmethod链式使用 """ def __init__(self, fget, *args, **kwargs): super().__init__(fget, *args, **kwargs) self.__doc__ = fget.__doc__ # 透传被装饰方法的抽象方法标记 self.__isabstractmethod__ = getattr(fget, "__isabstractmethod__", False) def __get__(self, instance, owner): # 抽象属性被访问时直接抛出符合要求的TypeError if self.__isabstractmethod__: raise TypeError( f"Can't instantiate abstract class {owner.__name__} with abstract methods {self.fget.__name__}" ) return self.fget(owner) class MyAbstractClass(ABC): @classproperty def non_abstract_class_property(self) -> str: """普通类属性示例,功能正常""" return "value 1" @classproperty @abstractmethod def abstract_class_property(self) -> str: """抽象类属性示例,子类必须实现""" pass class ConcreteNotImplemented(MyAbstractClass): """未实现抽象类属性的子类,会触发校验错误""" pass # 以下是测试代码,运行会依次触发对应错误 print("MyAbstractBaseClass TESTS") print(MyAbstractClass.non_abstract_class_property) print(MyAbstractClass.abstract_class_property) # 触发case1错误 print() print("ConcreteNotImplemented TESTS") print(ConcreteNotImplemented.non_abstract_class_property) print(ConcreteNotImplemented().abstract_class_property) # 触发case2错误 print(ConcreteNotImplemented.abstract_class_property) # 触发case3错误 print(ConcreteNotImplemented()) # 实例化时原生触发抽象类错误
运行效果说明
代码运行后会依次触发符合要求的错误:
- 访问
MyAbstractClass.abstract_class_property时抛出TypeError: Can't instantiate abstract class MyAbstractClass with abstract methods abstract_class_property,符合case1要求 - 实例化
ConcreteNotImplemented时ABC元类自动抛出同格式TypeError,符合case2要求 - 访问
ConcreteNotImplemented.abstract_class_property时抛出同格式TypeError,符合case3要求
内容的提问来源于stack exchange,提问作者Py38DS
相关产品推荐
相关产品推荐

