浅析Python中的多重继承


Posted in Python onApril 28, 2015

继承是面向对象编程的一个重要的方式,因为通过继承,子类就可以扩展父类的功能。

回忆一下Animal类层次的设计,假设我们要实现以下4种动物:

  1.     Dog - 狗狗;
  2.     Bat - 蝙蝠;
  3.     Parrot - 鹦鹉;
  4.     Ostrich - 鸵鸟。

如果按照哺乳动物和鸟类归类,我们可以设计出这样的类的层次:

浅析Python中的多重继承

但是如果按照“能跑”和“能飞”来归类,我们就应该设计出这样的类的层次:

浅析Python中的多重继承

如果要把上面的两种分类都包含进来,我们就得设计更多的层次:

  •     哺乳类:能跑的哺乳类,能飞的哺乳类;
  •     鸟类:能跑的鸟类,能飞的鸟类。

这么一来,类的层次就复杂了:

浅析Python中的多重继承

如果要再增加“宠物类”和“非宠物类”,这么搞下去,类的数量会呈指数增长,很明显这样设计是不行的。

正确的做法是采用多重继承。首先,主要的类层次仍按照哺乳类和鸟类设计:

class Animal(object):
  pass

# 大类:
class Mammal(Animal):
  pass

class Bird(Animal):
  pass

# 各种动物:
class Dog(Mammal):
  pass

class Bat(Mammal):
  pass

class Parrot(Bird):
  pass

class Ostrich(Bird):
  pass

现在,我们要给动物再加上Runnable和Flyable的功能,只需要先定义好Runnable和Flyable的类:

class Runnable(object):
  def run(self):
    print('Running...')

class Flyable(object):
  def fly(self):
    print('Flying...')

对于需要Runnable功能的动物,就多继承一个Runnable,例如Dog:

class Dog(Mammal, Runnable):
  pass

对于需要Flyable功能的动物,就多继承一个Flyable,例如Bat:

class Bat(Mammal, Flyable):
  pass

通过多重继承,一个子类就可以同时获得多个父类的所有功能。
Mixin

在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为Mixin。

为了更好地看出继承关系,我们把Runnable和Flyable改为RunnableMixin和FlyableMixin。类似的,你还可以定义出肉食动物CarnivorousMixin和植食动物HerbivoresMixin,让某个动物同时拥有好几个Mixin:

class Dog(Mammal, RunnableMixin, CarnivorousMixin):
  pass

Mixin的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个Mixin的功能,而不是设计多层次的复杂的继承关系。

Python自带的很多库也使用了Mixin。举个例子,Python自带了TCPServer和UDPServer这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixin和ThreadingMixin提供。通过组合,我们就可以创造出合适的服务来。

比如,编写一个多进程模式的TCP服务,定义如下:

class MyTCPServer(TCPServer, ForkingMixin):
  pass

编写一个多线程模式的UDP服务,定义如下:

class MyUDPServer(UDPServer, ThreadingMixin):
  pass

如果你打算搞一个更先进的协程模型,可以编写一个CoroutineMixin:

class MyTCPServer(TCPServer, CoroutineMixin):
  pass

这样一来,我们不需要复杂而庞大的继承链,只要选择组合不同的类的功能,就可以快速构造出所需的子类。
小结

由于Python允许使用多重继承,因此,Mixin就是一种常见的设计。

只允许单一继承的语言(如Java)不能使用Mixin的设计。

Python 相关文章推荐
Python的ORM框架中SQLAlchemy库的查询操作的教程
Apr 25 Python
Python实现按学生年龄排序的实际问题详解
Aug 29 Python
Python+pandas计算数据相关系数的实例
Jul 03 Python
pandas 将索引值相加的方法
Nov 15 Python
对Python3之方法的覆盖与super函数详解
Jun 26 Python
Python数学形态学实例分析
Sep 06 Python
python编写微信公众号首图思路详解
Dec 13 Python
PyCharm中关于安装第三方包的三个建议
Sep 17 Python
python matplotlib绘制三维图的示例
Sep 24 Python
Python自动化办公Excel模块openpyxl原理及用法解析
Nov 05 Python
python网络爬虫实现发送短信验证码的方法
Feb 25 Python
Python学习之时间包使用教程详解
Mar 21 Python
python输出当前目录下index.html文件路径的方法
Apr 28 #Python
Python实现基于权重的随机数2种方法
Apr 28 #Python
python使用urllib2实现发送带cookie的请求
Apr 28 #Python
python实现在windows下操作word的方法
Apr 28 #Python
介绍Python的@property装饰器的用法
Apr 28 #Python
Pyhthon中使用compileall模块编译源文件为pyc文件
Apr 28 #Python
在Python中使用__slots__方法的详细教程
Apr 28 #Python
You might like
Sony CFR 320 修复改造
2020/03/14 无线电
解析PHP计算页面执行时间的实现代码
2013/06/18 PHP
PHP中使用TCPDF生成PDF文档实例
2014/07/01 PHP
thinkPHP中验证码的简单实现方法
2016/12/05 PHP
各浏览器对link标签onload/onreadystatechange事件支持的差异分析
2011/04/27 Javascript
Jquery在指定DIV加载HTML示例代码
2014/02/17 Javascript
javascript学习笔记(六)数据类型和JSON格式
2014/10/08 Javascript
node.js开机自启动脚本文件
2014/12/24 Javascript
详解JavaScript函数对象
2015/11/15 Javascript
深入理解Java线程编程中的阻塞队列容器
2015/12/07 Javascript
jQuery层次选择器用法示例
2016/09/09 Javascript
Bootstrap CSS组件之下拉菜单(dropdown)
2016/12/17 Javascript
微信小程序wx.request实现后台数据交互功能分析
2017/11/25 Javascript
Vue实现web分页组件详解
2017/11/28 Javascript
vue源码解析之事件机制原理
2018/04/21 Javascript
Node.js 使用jade模板引擎的示例
2018/05/11 Javascript
vue自定义指令实现方法详解
2019/02/11 Javascript
详解JavaScript函数callee、call、apply的区别
2019/03/08 Javascript
JS画布动态实现黑客帝国背景效果
2020/11/08 Javascript
Vue与React的区别和优势对比
2020/12/18 Vue.js
Python中的__slots__示例详解
2017/07/06 Python
浅谈python可视化包Bokeh
2018/02/07 Python
[机器视觉]使用python自动识别验证码详解
2019/05/16 Python
python卸载后再次安装遇到的问题解决
2019/07/10 Python
在Django admin中编辑ManyToManyField的实现方法
2019/08/09 Python
Python制作词云图代码实例
2019/09/09 Python
python3光学字符识别模块tesserocr与pytesseract的使用详解
2020/02/26 Python
Selenium alert 弹窗处理的示例代码
2020/08/06 Python
使用CSS3编写类似iOS中的复选框及带开关的按钮
2016/04/11 HTML / CSS
NHL官方在线商店:Shop.NHL.com
2020/05/01 全球购物
Java中有几种方法可以实现一个线程?用什么关键字修饰同步方法?stop()和suspend()方法为何不推荐使用?
2015/08/04 面试题
工作期间打牌检讨书范文
2014/11/20 职场文书
浪漫的婚礼主持词
2015/06/30 职场文书
2015年度环卫处工作总结
2015/07/24 职场文书
python opencv旋转图片的使用方法
2021/06/04 Python
记一次Mysql不走日期字段索引的原因小结
2021/10/24 MySQL