Pro*_*o Q 5 python abstract-class exception class-properties
我花了很多时间研究这个,但没有一个答案看起来像我想要的那样.
我有一个带有类属性的抽象类,我希望每个子类都被强制实现
class AbstractFoo():
forceThis = 0
Run Code Online (Sandbox Code Playgroud)
所以,当我这样做
class RealFoo(AbstractFoo):
pass
Run Code Online (Sandbox Code Playgroud)
它会抛出一个错误,告诉我在实现之前它无法创建类forceThis.
我怎样才能做到这一点?
(我不希望该属性是只读的,但如果这是唯一的解决方案,我会接受它.)
对于一个类方法,我发现我可以做到
from abc import ABCMeta, abstractmethod
class AbstractFoo(metaclass=ABCMeta):
@classmethod
@abstractmethod
def forceThis():
"""This must be implemented"""
Run Code Online (Sandbox Code Playgroud)
以便
class RealFoo(AbstractFoo):
pass
Run Code Online (Sandbox Code Playgroud)
至少抛出错误 TypeError: Can't instantiate abstract class EZ with abstract methods forceThis
(虽然它不强制forceThis成为一种类方法.)
如何为类属性弹出类似的错误?
我根据之前发布的解决方案提出了一个解决方案。(谢谢@Daniel Roseman 和@martineau)
我创建了一个名为 ABCAMeta 的元类(最后一个“A”代表“属性”)。
班级有两种工作方式。
仅使用 ABCAMeta 作为元类的类必须有一个名为 的属性,required_attributes该属性应包含您想要该类的未来子类所需的所有属性的名称列表
父类元类为 ABCAMeta 的类必须具有其父类指定的所有必需属性。
例如:
class AbstractFoo(metaclass=ABCAMeta):
required_attributes = ['force_this']
class RealFoo(AbstractFoo):
pass
Run Code Online (Sandbox Code Playgroud)
会抛出错误:
NameError: Class 'RealFoo' has not implemented the following attributes: 'force_this'
正是我想要的。
from abc import ABCMeta
class NoRequirements(RuntimeError):
def __init__(self, message):
RuntimeError.__init__(self, message)
class ABCAMeta(ABCMeta):
def __init__(mcls, name, bases, namespace):
ABCMeta.__init__(mcls, name, bases, namespace)
def __new__(mcls, name, bases, namespace):
def get_requirements(c):
"""c is a class that should have a 'required_attributes' attribute
this function will get that list of required attributes or
raise a NoRequirements error if it doesn't find one.
"""
if hasattr(c, 'required_attributes'):
return c.required_attributes
else:
raise NoRequirements(f"Class '{c.__name__}' has no 'required_attributes' property")
cls = super().__new__(mcls, name, bases, namespace)
# true if no parents of the class being created have ABCAMeta as their metaclass
basic_metaclass = True
# list of attributes the class being created must implement
# should stay empty if basic_metaclass stays True
reqs = []
for parent in bases:
parent_meta = type(parent)
if parent_meta==ABCAMeta:
# the class being created has a parent whose metaclass is ABCAMeta
# the class being created must contain the requirements of the parent class
basic_metaclass=False
try:
reqs.extend(get_requirements(parent))
except NoRequirements:
raise
# will force subclasses of the created class to define
# the attributes listed in the required_attributes attribute of the created class
if basic_metaclass:
get_requirements(cls) # just want it to raise an error if it doesn't have the attributes
else:
missingreqs = []
for req in reqs:
if not hasattr(cls, req):
missingreqs.append(req)
if len(missingreqs)!=0:
raise NameError(f"Class '{cls.__name__}' has not implemented the following attributes: {str(missingreqs)[1:-1]}")
return cls
Run Code Online (Sandbox Code Playgroud)
有任何改进建议欢迎在评论中提出。
| 归档时间: |
|
| 查看次数: |
1257 次 |
| 最近记录: |