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

Gle*_*ord 31 python inheritance

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

我的理解是Python不支持创建不能被子类化的类(最终类).但是,在我看来,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
Run Code Online (Sandbox Code Playgroud)

相关问题: 为什么我不能在Python中扩展bool?

Dun*_*can 47

您可以非常轻松地模拟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
Run Code Online (Sandbox Code Playgroud)

将给出以下输出:

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
Run Code Online (Sandbox Code Playgroud)


ken*_*ytm 13

您只能通过C API执行此操作.清除Py_TPFLAGS_BASETYPE的位tp_flags的类型的对象.

像这样:http://svn.python.org/projects/python/trunk/Objects/boolobject.c(vs intobject.c where where Py_TPFLAGS_BASETYPEset).


Nei*_*l G 7

在 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
Run Code Online (Sandbox Code Playgroud)

在 Python 3.8 中,您还应该使用final装饰器来引发类型检查错误:

from typing import final


@final
class SomeBase:
    ...
Run Code Online (Sandbox Code Playgroud)

类型检查由 MyPy 之类的程序完成,它们是可选的。


sob*_*evn 6

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()
Run Code Online (Sandbox Code Playgroud)

并带有常数:

from typing_extensions import Final

DAYS_IN_A_WEEK: Final = 7
DAYS_IN_A_WEEK = 8  # mypy will raise an error
Run Code Online (Sandbox Code Playgroud)

我们还有一个小库来编写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`
    ...
Run Code Online (Sandbox Code Playgroud)

特征:

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

  • `typing.final` 不是同一件事,它是关于 steriods 的文档,一个静态分析工具,而不是对子类化的运行时强制限制。作为“不同的用例”,这并不是真正的“功能”。 (2认同)