推出继承的初衷是让新手顺利使用只有专家才能设计出来的框架。
——Alan Kaypython
import collections class DoppelDict2(collections.UserDict): def __setitem__(self, key, value): super().__setitem__(key, [value] * 2) dd = DoppelDict2(one=1) print(dd) dd['two'] = 2 print(dd) dd.update(three=3) print(dd) class AnswerDict2(collections.UserDict): def __getitem__(self, key): return 42 ad = AnswerDict2(a='foo') print(ad["a"])
class A: def ping(self): print('ping:', self) class B(A): def pong(self): print('pong:', self) class C(A): def pong(self): print('PONG:', self) class D(B, C): def ping(self): super().ping() print('post-ping:', self) def pingpong(self): self.ping() super().ping() self.pong() super().pong() C.pong(self) d = D() d.pong() C.pong(d) #看继承关系 print(D.__mro__)
直接调用 d.pong() 运行的是 B 类中的版本。程序员
Python 能区分 d.pong() 调用的是哪一个方法,是由于 Python 会按照特定的顺序遍历继承图。
这个顺序叫方法解析顺序(Method Resolution Order,MRO)。
类都有一个名为__mro__ 的属性,它的值是一个元组,按照方法解析顺序列出各个超类,从当前类一直向上,直到 object 类。D
然而,使用 super() 最安全,也不易过期。调用框架或不受本身控制的类层次结构中的
方法时,尤为适合使用 super()。设计模式
1 多重继承能发挥积极做用。
2 《设计模式:可复用面向对象软件的基础》一书中的适配器模式用的就是多重继承,所以使用多重继承确定没有错
3(那本书中的其余 22 个设计模式都使用单继承,所以多重继承显然不是灵丹妙药)安全
下面是避免把类图搅乱的一些建议。app
使用多重继承时,必定要明确一开始为何建立子类。主要缘由可能有:框架
继承接口,建立子类型,实现“是什么”关系
继承实现,经过重用避免代码重复
其实这两条常常同时出现,不过只要可能,必定要明确意图。经过继承重用代码是实
现细节,一般能够换用组合和委托模式。而接口继承则是框架的支柱。post
现代的 Python 中,若是类的做用是定义接口,应该明确把它定义为抽象基类。Python
3.4 及以上的版本中,咱们要建立 abc.ABC 或其余抽象基类的子类
python没有interface这种定义设计
class Widget(BaseWidget, Pack, Place, Grid): """Internal class. Base class for a widget which can be positioned with the geometry managers Pack, Place or Grid.""" pass
Widget 类的定义体是空的,可是这个类提供了有用的服务:code
把四个超类结合在一块儿,这样须要建立新小组件的用户无需记住所有混入,也不用担忧声明 class 语句时有没有遵照特定的顺序。
这句话引自《设计模式:可复用面向对象软件的基础》一书, 这是我能提供的最佳
建议。对象
熟悉继承以后,就太容易过分使用它了。出于对秩序的诉求,咱们喜欢按整洁
的层次结构放置物品,程序员更是乐此不疲。
即使是单继承,这个原则也能提高灵活性,由于子类化是
一种紧耦合,并且较高的继承树容易倒。
page 417 这里有些复杂,等我牛掰了再来看
collections.abc 模块中相应的抽象基类
多重继承这把双刃剑。首先,咱们说明了 mro 类属性中蕴藏的方法解析顺序,有了这一机制,继承方法的名称再也不会发生冲突不要子类化内置类型,用户本身定义的类应该继承 collections 模块的类