【问题标题】:How does python prevent a class from being subclassed? [duplicate]python如何防止类被子类化? [复制]
【发布时间】:2013-04-17 09:36:42
【问题描述】:

我在python docs看到了以下内容:

bool([x])

使用标准真值测试程序将值转换为布尔值。如果 x 为假或省略,则返回 False;否则它 返回真。 bool 也是一个类,它是 int 的子类。 类 bool 不能被进一步子类化。 它的唯一实例是 False 和 没错。

我这辈子从没想过继承bool,但我自然而然地立即尝试了,果然:

>>> class Bool(bool):
    pass

Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    class Bool(bool):
TypeError: Error when calling the metaclass bases
    type 'bool' is not an acceptable base type

所以,问题是:这是如何完成的?我可以应用相同的技术(或不同的技术)将我自己的类标记为final,即防止它们被子类化吗?

【问题讨论】:

  • 你为什么不想继承bool?您可以创建10 子类来表示每个可能的布尔状态。
  • 感谢@Martijn,这看起来确实是一个密切相关的问题。它在我的 SO 搜索过程中没有出现(我应该考虑在搜索词中添加“final”)。

标签: python subclass final


【解决方案1】:

bool 类型是在 C 中定义的,它的tp_flags 槽故意不包含Py_TPFLAGS_BASETYPE flag

C 类型需要将自己明确标记为可子类化。

要对自定义 Python 类执行此操作,请使用元类:

class Final(type):
    def __new__(cls, name, bases, classdict):
        for b in bases:
            if isinstance(b, Final):
                raise TypeError("type '{0}' is not an acceptable base type".format(b.__name__))
        return type.__new__(cls, name, bases, dict(classdict))

class Foo:
    __metaclass__ = Final

class Bar(Foo):
    pass

给予:

>>> class Bar(Foo):
...     pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __new__
TypeError: type 'Foo' is not an acceptable base type

【讨论】:

  • 谢谢,已经涵盖了!
  • 经过进一步思考,我有一个问题:检查isinstance(b, Final) 有什么目的吗?我的意思是,这个__new__ 只会被一个继承自Final 的类调用,那么为什么不直接在cls != 'Final' 上调用呢?
  • @alexis:是的,因为您需要命名您尝试从哪个基类继承。 Bar 不是Final 的子类,它是Foo 的子类,这就是isinstance(b, Final) 测试为该类返回True 的原因。如果使用了更多基类,您需要告诉最终用户其中哪一个基类不可继承。
  • 知道了,对,它在元类中,而不是最终类本身。谢谢!
  • 需要注意的是,这只是为了理解 Python 是如何工作的。任何人都不应该在真正的程序中构建这样的东西。
猜你喜欢
  • 2021-05-11
  • 1970-01-01
  • 1970-01-01
  • 2016-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-26
  • 2017-08-27
相关资源
最近更新 更多