12.1 子类化内置类型很麻烦
使用 C 语言实现的内置类型不会调用用户顶以的类覆盖的特殊方法,如 dict
的子类覆盖的 __getitem__()
方法不会被内置类型的 get()
方法调用。
具体我们可以看看下面的例子:
1 |
|
所以,直接实例化内置类型(如 dict
,list
或 str
)容易出错,用户自己定义的类,应该继承 collections
模块中的类,如 UserDict
,UserList
和 UserString
,这样就不会出现内置类型不调用子类覆盖的特殊方法的尴尬场面。
12.2 多重继承和方法的解析顺序
Python 会按照特定的顺序遍历继承图来决定如何解析子类调用的方法,这个顺序叫做方法解析顺序(Method Resolution Order)。每个类都有一个名为 __mro__
的属性,它的值是一个元组,按照方法解析顺序列出该类的各个超类,同时,MRO 还与类声明超类的顺序有关。
12.4 处理多重继承
- 把接口继承和实现继承区分开:继承接口是为了实现“是什么”的关系,继承实现是为了重用代码
- 使用抽象基类表示接口
- 通过混入重用代码:如果一个类的作用是为多个不相关的子类提供方法实现,从而实现重用,但不体现“是什么”关系,应该把那个类明确地定义为混入类(mixin class)。从概念上讲,混入不定义新类型,只是打包方法,便于重用。
- 在名称中明确指明混入:混用类的类名强烈建议使用 Mixin 作为后缀。
- 抽象基类可以作为混入,反过来则不成立
- 不要子类化多个具体类:具体类的超类中除了一个具体超类之外,其余的应该都是抽象基类或混入
- 为用户提供聚合类:如果抽象基类或混入的组合对客户代码非常有用,那就提供一个类,使用易于理解的方式把它们结合起来。
- 优先使用对象组合而不是类继承