流畅的python读书笔记-第十章-继承优缺点
继承的优缺点
推出继承的初衷是让新手顺利使用只有专家才能设计出来的框架。
——Alan Kay
子类化内置类型很麻烦 (如 list 或 dict)) ,别搞这种
- 直接子类化内置类型(如 dict、list 或 str)容易出错,因为内置类型的 方法通常会忽略用户覆盖的方法。
- 不要子类化内置类型,用户自己定义的类应该继承 collections 模块的类,
- 例如UserDict、UserList 和 UserString,这些类做了特殊设计,因此易于扩展。
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"])
- 综上,本节所述的问题只发生在 C 语言实现的内置类型内部的方法委托上,而且只影响 直接继承内置类型的用户自定义类。
- 如果子类化使用 Python 编写的类,如 UserDict 或 MutableMapping,就不会受此影响。
多重继承和方法解析顺序
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 个设计模式都使用单继承,因此多重继承显然不是灵丹妙药)
处理多重继承
下面是避免把类图搅乱的一些建议。
01. 把接口继承和实现继承区分开
使用多重继承时,一定要明确一开始为什么创建子类。主要原因可能有:
继承接口,创建子类型,实现“是什么”关系
继承实现,通过重用避免代码重复
其实这两条经常同时出现,不过只要可能,一定要明确意图。通过继承重用代码是实
现细节,通常可以换用组合和委托模式。而接口继承则是框架的支柱。
02. 使用抽象基类显式表示接口
现代的 Python 中,如果类的作用是定义接口,应该明确把它定义为抽象基类。Python
3.4 及以上的版本中,我们要创建 abc.ABC 或其他抽象基类的子类
python没有interface这种定义
03. 通过混入重用代码
- 一个类的作用是为多个不相关的子类提供方法实现
- 应该把那个类明确地定义为混入类(mixin class)
- 从概念上讲,混入不定义新类型,只是打包方法,便于重用。
- 混入类绝对不能实例化,而且具体类不能只继承混入类。
- 混入类应该提供某方面的特定行为,只实现少量关系非常紧密的方法。
04. 在名称中明确指明混入
- 因为在 Python 中没有把类声明为混入的正规方式,所以强烈推荐在名称中加入...Mixin 后缀。
- Tkinter 没有采纳这个建议,如果采纳的话,XView 会变成XViewMixin,Pack 会变成 PackMixin
05. 为用户提供聚合类
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 类的定义体是空的,但是这个类提供了有用的服务:
把四个超类结合在一起,这样需要创建新小组件的用户无需记住全部混入,也不用担心声明 class 语句时有没有遵守特定的顺序。
08. “优先使用对象组合,而不是类继承”
这句话引自《设计模式:可复用面向对象软件的基础》一书, 这是我能提供的最佳
建议。
熟悉继承之后,就太容易过度使用它了。出于对秩序的诉求,我们喜欢按整洁
的层次结构放置物品,程序员更是乐此不疲。
即便是单继承,这个原则也能提升灵活性,因为子类化是
一种紧耦合,而且较高的继承树容易倒。
继承在Django的应用
page 417 这里有些复杂,等我牛掰了再来看
总结
collections.abc 模块中相应的抽象基类
多重继承这把双刃剑。首先,我们说明了 mro 类属性中蕴藏的方法解析顺序,有了这一机制,继承方法的名称不再会发生冲突
不要子类化内置类型,用户自己定义的类应该继承 collections 模块的类
最新文章
- SQL 一条记录的的两个字段值相同与不同的查询
- Android adb命令 一
- dedecms \plus\guestbook.php SQL Injection Vul By \plus\guestbook\edit.inc.php
- myeclipse下拷贝的项目,tomcat下部署名称和导出为war包的名称默认值修改
- java练习题:解一元二次方程、判断闰年、判断标准身材、三个数取最大值
- 《深度探索C++对象模型》3
- JQuery基础教程:事件(下)
- 查看Linux发行版的名称和版本号
- (转)Discuz!NT图文安装教程
- Struts2.0+Spring3+Hibernate3(SSH~Demo)
- PHP count() 函数
- Linux获取UUID
- python 模块与包
- 初见SDN
- css3 简易时钟
- 6 关于plsql中文显示乱码问题
- 7、Kafka、AMQ、RabbitMQ对比
- 面试 -- requestLayout、invalidate与postInvalidate区别
- Flume+Kafka整合
- ROS学习(十一)—— msg srv
热门文章
- CentOS 7 Docker安装
- 用人话告诉小白:什么是项目管理(例如Maven),什么是调试工具(即debugger),什么是编译(即compile)
- iOS岗位招聘标准水涨船高,五年iOS程序员表示面试太难了
- 初探CI,Github调戏Action手记——自动构建并发布
- 在IDEA中搭建Java源码学习环境并上传到GitHub上
- syncronized如何上锁
- L8梯度消失、梯度爆炸
- K - Downgrade Gym - 101775K
- Crossing River POJ过河问题
- MVC5+EasyUI+EF6增删改查的演示