我有这个抽象类
class Kuku(ABC):
def __init__(self):
self.a = 4
@property
@abstractmethod
def kaka(self):
pass
kaka
是一个抽象属性,所以我希望 python 强制它成为继承者中的一个属性,但它允许我创建:
class KukuChild(Kuku):
def kaka(self):
return 3
KukuChild().kaka() 返回 3,就好像它不是属性一样。这是故意的吗? Pycharm 也不强制执行此操作,那么为什么还要添加property
抽象类中的装饰器?
我自己也遇到过这个问题,在研究了如何强制执行此类行为的选项之后,我提出了实现具有该类型检查的类的想法。
import abc
import inspect
from typing import Generic, Set, TypeVar, get_type_hints
T = TypeVar('T')
class AbstractClassVar(Generic[T]):
pass
class Abstract(abc.ABC):
"""Inherit this class to:
1. Enforce type checking for abstract properties.
2. Check that abstract class members (aka. `AbstractClassVar`) are implemented.
"""
def __init_subclass__(cls) -> None:
def get_abstract_properties(cls) -> Set[str]:
"""Gets a class's abstract properties"""
abstract_properties = set()
if cls is Abstract:
return abstract_properties
for base_cls in cls.__bases__:
abstract_properties.update(get_abstract_properties(base_cls))
abstract_properties.update(
{abstract_property[0] for abstract_property in
inspect.getmembers(cls, lambda a: getattr(a, "__isabstractmethod__", False) and type(a) == property)})
return abstract_properties
def get_non_property_members(cls) -> Set[str]:
"""Gets a class's non property members"""
return {member[0] for member in inspect.getmembers(cls, lambda a: type(a) != property)}
def get_abstract_members(cls) -> Set[str]:
"""Gets a class's abstract members"""
abstract_members = set()
if cls is Abstract:
return abstract_members
for base_cls in cls.__bases__:
abstract_members.update(get_abstract_members(base_cls))
for (member_name, annotation) in get_type_hints(cls).items():
if getattr(annotation, '__origin__', None) is AbstractClassVar:
abstract_members.add(member_name)
return abstract_members
cls_abstract_properties = get_abstract_properties(cls)
cls_non_property_members = get_non_property_members(cls)
# Type checking for abstract properties
if cls_abstract_properties:
for member in cls_non_property_members:
if member in cls_abstract_properties:
raise TypeError(f"Wrong class implementation {cls.__name__} " +
f"with abstract property {member}")
# Implementation checking for abstract class members
if Abstract not in cls.__bases__:
for cls_member in get_abstract_members(cls):
if not hasattr(cls, cls_member):
raise NotImplementedError(f"Wrong class implementation {cls.__name__} " +
f"with abstract class variable {cls_member}")
return super().__init_subclass__()
Usage:
class Foo(Abstract):
foo_member: AbstractClassVar[str]
@property
@abc.abstractmethod
def a(self):
...
class UpperFoo(Foo):
# Everything should be implemented as intended or else...
...
- 不实现抽象属性
a
或将其实现为除property
(type) 将导致 TypeError
- 类成员的技巧完全不同,并使用更复杂的注释方法,但结果几乎相同。
没有实现抽象类成员
foo_member
将导致 NotImplementedError。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)