哪些类不能被子类化?
Posted
技术标签:
【中文标题】哪些类不能被子类化?【英文标题】:Which classes cannot be subclassed? 【发布时间】:2012-04-21 03:35:43 【问题描述】:对于哪些内置和标准库类不可子类化(“final”)有什么规定吗?
从 Python 3.3 开始,以下是一些示例:
bool
function
operator.itemgetter
slice
我找到了一个question,它处理“最终”类的实现,包括 C 和纯 Python。
我想了解什么原因可以解释为什么首先选择一个类作为“最终”类。
【问题讨论】:
NoneType
是另一个例子。
一个 Python 实现中的最终类可以在另一个实现中子类化吗?我希望有人可以确认它永远不会发生。否则,为一个实现编写的代码在移植到另一个实现时可能会中断(同样非常痛苦:想象一下,如果有人继承了function
,现在需要重构代码以避免这种继承)。
请注意,PyPy 也拒绝对您的四个示例进行子类化......即使它没有 CPython 限制。他们的代码库中可能记录了一个原因。
NotImplementedType
(即type(NotImplemented)
)和ellipsis
(即type(...)
)是另外两个例子。与None
一样,没有理由拥有多个这些类的实例,如果允许,检查它们会更尴尬(if x is None
必须变为if isinstance(x, type(None))
)。我想,原则上,您可以通过查看类型定义中tp_flags
值的来源来获得完整列表。
@agf:请参阅this post,了解为什么要继承itemgetter
;和this post 解释为什么你可能想要子类function
(这个是旧的,所以其中一些参数可能不适用)。
【参考方案1】:
一个类在 Python 中成为“final”似乎有两个原因。
1.违反类不变量
遵循单例模式的类具有一个不变量,即实例数量有限(预先确定)。在子类中任何违反此不变量的行为都将与该类的意图不一致,并且无法正常工作。例子:
bool
:True
,False
;见Guido's comments
NoneType
: None
NotImplementedType
: NotImplemented
ellipsis
: Ellipsis
在这个类别中可能有除单例模式以外的情况,但我不知道。
2.没有说服力的用例
在 C 中实现的类需要额外的工作以允许子类化(至少在 CPython 中)。在没有令人信服的用例的情况下做这样的工作并不是很有吸引力,因此志愿者不太可能挺身而出。例子:
function
;见Tim Peters' post
注1:
我最初认为有有效的用例,但对function
和operator.itemgetter
的子类化兴趣不足。感谢@agf 指出here 和here 提供的用例并不令人信服(请参阅@agf cmets 的问题)。
注2:
我担心另一个 Python 实现可能会意外地允许子类化 CPython 中的 final 类。这可能会导致代码不可移植(一个用例可能很弱,但如果他们的 Python 支持,有人可能仍会编写子类function
的代码)。这可以通过在 Python 文档中标记所有不能被子类化的内置和标准库类来解决,并要求所有实现在这方面都遵循 CPython 行为。
注3:
CPython 在上述所有情况下产生的消息是:
TypeError: type 'bool' is not an acceptable base type
正如许多关于这个主题的问题所显示的那样,它非常神秘。我将提交一个建议,在文档中添加一个段落来解释最终类,甚至可能将错误消息更改为:
TypeError: type 'bool' is final (non-extensible)
【讨论】:
当然,如果您正在编写薛定谔猫的模拟,您可能希望将bool
子类化为包含unknown
:-P 只是在开玩笑
@Endophage:Qbit 肯定是一种有用的类型,但它不是bool
的子类,事实上,恰恰相反,每个布尔值都是一种 qbit!一个恰好被观察到的。不过,我可能会和__subclasscheck__
和朋友一起处理这个案子。
@TokenMacGuy 出色的观察!那么为什么我们不在 Python 中有一个 Qbit 类,它是 bool 的子类!我要求它应该是这样! :-P
但在观察/测试时,Qbit 的值将始终为 False 或 True。似乎你只需要一个 bool 的子类,它只在观察时进行“计算”......(LazyBool
)
@SingleNegationElimination @Endophage 也许这就是为什么bool
不能是Enum
基类的原因,Guido 不玩骰子?以上是关于哪些类不能被子类化?的主要内容,如果未能解决你的问题,请参考以下文章