哪些类别不能被子类别化?


75

是否有关于哪些内置库和标准库类不可归类(“最终”)的规则?

从Python 3.3开始,以下是一些示例:

  • bool
  • function
  • operator.itemgetter
  • slice

我发现了一个问题,涉及用C语言和纯Python实现“最终”类。

我想了解什么原因可以解释为什么首先选择一个班级是“最终的”。


6
NoneType是另一个例子。
邓肯

4
一个Python实现中的最终类是否可以在另一实现中子类化?我希望有人可以确认它永远不会发生。否则,为一种实现编写的代码在移植到另一种实现时可能会中断(也非常痛苦:想象是否有人function继承了该类,现在需要重构代码以避免这种继承)。
最大

3
请注意,即使PyPy没有CPython限制,它也拒绝继承您的四个示例。他们的代码库中可能记录了一个原因。
Matt B.

4
NotImplementedType(即type(NotImplemented))和ellipsis(即type(...))是另外两个示例。像一样None,没有理由要有多个这些类的实例,并且如果允许这样做,则检查它们if x is None会比较尴尬(必须成为if isinstance(x, type(None)))。我想,原则上,通过查看tp_flags类型定义中in值的来源,您可以获得完整的列表。
詹姆斯

2
@agf:请参阅此文章以了解为什么要继承类itemgetter;而这个帖子为什么你可能想子类function(这一个是旧的,所以其中的一些参数可能不适用)。
最大

Answers:


31

在Python中,类最终是有两个原因的。

1.违反类别不变式

遵循Singleton模式的类具有不变的数量,即实例数量有限(预定)。子类中对此不变量的任何违反都将与该类的意图不一致,并且将无法正常工作。例子:

  • boolTrueFalse; 参见Guido的评论
  • NoneTypeNone
  • NotImplementedTypeNotImplemented
  • ellipsisEllipsis

在此类别中,可能还有Singleton模式以外的情况,但我不知道有任何情况。

2.没有说服力的用例

用C实现的类需要额外的工作才能允许子类化(至少在CPython中)。在没有令人信服的用例的情况下进行此类工作并不是很有吸引力,因此志愿者不太可能挺身而出。例子:

注1:

我最初认为function和的子类化存在有效的用例,但兴趣不足operator.itemgetter。感谢@agf指出这里此处提供的用例并不令人信服(请参阅问题的@agf注释)。

笔记2:

我担心的是,另一个Python实现可能会意外地允许继承CPython中最终的类。这可能会导致代码不可移植(用例可能很弱,但是如果某人function的Python支持,则仍可能编写子类的代码)。这可以通过在Python文档中标记所有不能被子类化的内置库和标准库类来解决,并要求所有实现在这方面都遵循CPython行为。

注3:

在上述所有情况下,CPython生成的消息是:

TypeError: type 'bool' is not an acceptable base type

正如这个问题上的许多问题所显示的,这是非常神秘的。我将提出一个建议,在说明最终课程的文档中添加一个段落,甚至可能将错误消息更改为:

TypeError: type 'bool' is final (non-extensible)

5
当然,如果您正在编写薛定boolunknown
inger

9
@Endophage:Qbit当然是有用的类型,但它不是的子类bool,实际上,相反,每个布尔值都是一种qbit!一种恰好被观察到。不过,我可能会__subclasscheck__和和朋友一起处理这种情况。
SingleNegationElimination 2012年

5
@TokenMacGuy非常棒的观察!那么为什么我们在Python中没有Qool类,而bool是它的子类呢!我要求应该是这样!:-P
Endophage 2012年

但是,在观察/测试时,Qbit的值将始终为False或True。似乎您只需要bool的子类,该子类仅在观察时执行其“计算”...。(LazyBool
DylanYoung
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.