本章对继承的讨论先从子类化内置类型引起的问题谈起:内置类型的原生方法使用 C 语言实现,不会调用子类中覆盖的方法,不过有极少数例外。因此,需要定制 listdictstr 类型时,子类化 UserListUserDictUserString 更简单。这些类在 collections 模块(https://docs.python.org/3/library/collections.html)中定义,它们其实是对内置类型的包装,会把操作委托给内置类型——这是标准库中优先选择组合而不使用继承的三个例子。如果所需的行为与内置类型区别很大,或许更容易的做法是,子类化 collections.abc 模块(https://docs.python.org/3/library/collections.abc.html)中相应的抽象基类,然后自己实现。

本章余下的内容着重探讨了多重继承这把双刃剑。首先,我们说明了 __mro__ 类属性中蕴藏的方法解析顺序,有了这一机制,继承方法的名称不再会发生冲突。我们还提到,内置的 super() 函数会按照 __mro__ 属性给出的顺序调用超类的方法。然后,我们分析了 Python 标准库中 GUI 工具包 Tkinter 对多重继承的运用。Tkinter 不能代表当前的最佳实践,因此我们讨论了处理多重继承的一些方式,例如谨慎使用混入类,以及借助组合模式彻底避免使用多重继承。指出 Tkinter 对多重继承的使用已经到了滥用的程度后,我们在最后一节分析了 Django 基于类的视图,了解了它们的核心层次结构。我觉得这更好地利用了混入。

Lennart Regebro(一位经验非常丰富的 Python 程序员,也是本书的技术审校之一)发现 Django 通过混入设计的视图层次结构有点混乱。但是他又写道:

多重继承的危害和缺点被放大了。我从来不觉得它是什么大问题。

总之,每个人对如何使用以及要不要在自己的项目中使用多重继承都有自己的观点。但是,我们往往没得选择,因为我们必须使用的框架有它们自己的选择。