Python 3.x中的最后一课 - Guido没有告诉我什么?

时间:2010-05-13 08:35:43

标签: python inheritance

这个问题建立在许多假设之上。如果一个假设是错误的,那么整个事情就会失败。我还是相对较新的Python,刚刚进入了好奇/探索阶段。

我的理解是Python不支持创建不能被子类化的类( final 类)。但是,在我看来,Python中的 bool 类不能被子类化。当考虑bool类的意图时,这是有道理的(因为bool只应该有两个值:true和false),我很满意。我想知道的是 这个类被标记为最终的。

所以我的问题是: Guido如何成功阻止bool的子类化?

>>> class TestClass(bool):
        pass

Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    class TestClass(bool):
TypeError: type 'bool' is not an acceptable base type

相关问题: Why I can't extend bool in Python?

4 个答案:

答案 0 :(得分:45)

您可以非常轻松地模拟Python 3.x中的相同效果:

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 C(metaclass=Final): pass

class D(C): pass

将提供以下输出:

Traceback (most recent call last):
  File "C:\Temp\final.py", line 10, in <module>
    class D(C): pass
  File "C:\Temp\final.py", line 5, in __new__
    raise TypeError("type '{0}' is not an acceptable base type".format(b.__name__))
TypeError: type 'C' is not an acceptable base type

答案 1 :(得分:13)

您只能通过C API执行此操作。清除类型对象tp_flags的{​​{3}}位。

喜欢这样:Py_TPFLAGS_BASETYPE(对http://svn.python.org/projects/python/trunk/Objects/boolobject.c设置了Py_TPFLAGS_BASETYPE。)

答案 2 :(得分:1)

在Python 3.6中,您可以阻止子类化,而无需使用如下这样的元类:

class SomeBase:

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        if cls is not SomeBase:
            raise TypeError("SomeBase does not support polymorphism.  Use composition over inheritance.")


class Derived(SomeBase):
    pass

答案 3 :(得分:1)

Final@final类型现在在typing_extensions中可用。

我写了一篇文章,涵盖了这种新类型的几乎所有部分:https://sobolevn.me/2018/07/real-python-contants

一些带有类的示例:

from typing_extensions import final

@final
class HRBusinessUnit(AbstractBusinessUnit):
    def grant_permissions(self) -> None:
        self.api.do_some_hr_stuff()


class SubHRBusinessUnit(HRBusinessUnit):  # mypy will raise an error
    def grant_permissions(self) -> None:
        self.api.do_some_it_stuff()

并带有常量:

from typing_extensions import Final

DAYS_IN_A_WEEK: Final = 7
DAYS_IN_A_WEEK = 8  # mypy will raise an error

我们还有一个小的库,可以编写final类,这些类也可以在运行时检查! https://github.com/wemake-services/final-class

from final_class import final


@final
class Example(object):  # You won't be able to subclass it!
    ...


class Error(Example):  # Raises `TypeError`
    ...

功能:

  • 没有元类冲突
  • 没有运行时开销
  • 没有依赖项
  • 包括类型提示
  • 设计得尽可能简单