有没有任何关于元类或__init_subclass__
应该引发哪种异常来强制实现子类中的某些不变量的好惯例?
对于这个问题的回答,我会接受Python内置行为、PEP、标准库或成熟的第三方库的先例,或者为什么应该以某种方式完成的令人信服的推理。
TypeError
:
>>> class MorePowerfulTuple(tuple): pass
... __slots__ = ('power',)
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: nonempty __slots__ not supported for subtype of 'tuple'
bool
, it raises a TypeError
:
>>> class BetterBool(bool): pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'bool' is not an acceptable base type
>>> class StrongerFasterMethodType(types.MethodType):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'bound_method' is not an acceptable base type
TypeError :您可以将 __slots__ =('power',)
替换为 __slots__ =()
,它仍然可以工作。因此,至少在语言本身的参考实现中,我们已经有了一个实例,其中一个子类化错误被报告为 TypeError ,即使在许多其他情况下,使用空可迭代对象而不是具有一个或多个元素的可迭代对象更合适应该是一个 ValueError 。
似乎在内置异常层次结构中没有专门为此目的设计的类。
此外,该文档排除了尝试使用多重继承来子类化这些错误(在某些情况下可能很诱人 - 例如,元类或__init_subclass__
的实现者可能会想象一个工厂函数根据某些参数动态地在程序执行过程中制作子类,并认为引发更精确的错误,如ValueError
,会有所帮助 - 因此,开发人员可能会决定将TypeError
和ValueError
及其自己的子类错误和ValueError
相乘,而不是像上面内置类的预先设置那样仅引发一个普通的TypeError
),因为该文档明确建议不要从多个异常类型进行子类化,因为内部实现细节可以自由地以使它们无法同时用作基类的方式实现不同的异常:
有些异常类型具有自定义的内存布局,这使得创建继承自多个异常类型的子类成为不可能。类型的内存布局是一项实现细节,可能会在 Python 版本之间发生变化,从而在未来引起新的冲突。因此,建议完全避免继承多个异常类型。
我不知道是否有任何PEP、标准库或第三方库建立了特定的实践方法。
(然而,肯定有像namedtuple、dataclasses、attrs这样的库,甚至像SQLAlchemy和Pydantic这样根据用户参数自动生成类的库,可能值得研究它们自己的示例。)
@abs.abstractmethod
方法的abc.ABC
类,并尝试实例化任何未完全重写所有这些abstractmethod
的类,以获得该方法的非抽象覆盖,则会出现TypeError: Can't instantiate abstract class Foo with abstract method foo
错误(对于class Foo(abc.ABC):
,@abc.abstractmethod
为def foo(self): raise NotImplementedError
)。这不是类定义不变式,但它具有相同的目的; 未定义所有抽象方法的类将考虑构建它时出现TypeError
。 - ShadowRanger