Gui*_*the 3 python metaclass python-3.x python-object
我一直在尝试验证用户可以在框架样式设置中创建的类。我可以通过以下方式确保子类中存在类属性:
from abc import ABC, abstractmethod
class A(ABC):
@property
@classmethod
@abstractmethod
def s(self):
raise NotImplementedError
class ClassFromA(A):
pass
ClassFromA()
Run Code Online (Sandbox Code Playgroud)
这导致以下情况Exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class ClassFromA with abstract methods s
Run Code Online (Sandbox Code Playgroud)
我还可以s在创建类时使用装饰器检查类属性的类型,如下所示:
from abc import ABC, abstractmethod
def validate_class_s(cls):
if not isinstance(cls.s, int):
raise ValueError("S NOT INT!!!")
return cls
class A(ABC):
@property
@classmethod
@abstractmethod
def s(self):
raise NotImplementedError
@validate_class_s
class ClassFromA(A):
s = 'a string'
Run Code Online (Sandbox Code Playgroud)
导致:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 3, in validate_class_s
ValueError: S NOT INT!!!
Run Code Online (Sandbox Code Playgroud)
这在最终检查类属性时很有用。但这会导致冗长的类定义,其中每个子类都必须进行修饰。
有没有办法验证s基类中的类属性(在示例中)?最好不要太冗长?
您可以使用 Python 3.6 中的新__init_subclass__功能。
这是在您的基类上定义的类方法,将在创建时为每个创建的子类调用一次。对于大多数断言用例,它可能比 Python 的 ABC 更有用,后者只会在类实例化时间引发错误(相反,如果您想在进入具体类之前对其他抽象类进行子类化,则必须在您的代码)。
因此,例如,如果您想通过在基类上进行注释来指示子类上所需的方法和属性,您可以执行以下操作:
_sentinel = type("_", (), {})
class Base:
def __init_subclass__(cls, **kwargs):
errors = []
for attr_name, type_ in cls.__annotations__.items():
if not isinstance(getattr(cls, attr_name, _sentinel), type_):
errors.append((attr_name, type))
if errors:
raise TypeError(f"Class {cls.__name__} failed to initialize the following attributes: {errors}")
super().__init_subclass__(**kwargs)
s: int
class B(Base):
pass
Run Code Online (Sandbox Code Playgroud)
您可以collections.abc.Callable为需要方法添加注释,或者(type(None), int)为可选整数添加元组,但isinstance不幸的是,它 不适用于“打字”模块提供的通用语义。如果你想这样做,我建议看看pydantic项目并利用它。
| 归档时间: |
|
| 查看次数: |
518 次 |
| 最近记录: |