浅析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文件写入实例分析
Apr 08 Python
详解python中的time和datetime的常用方法
Jul 08 Python
python opencv将图片转为灰度图的方法示例
Jul 31 Python
pandas 空数据处理方法详解
Nov 02 Python
python实现门限回归方式
Feb 29 Python
解决python父线程关闭后子线程不关闭问题
Apr 25 Python
Python基于模块Paramiko实现SSHv2协议
Apr 28 Python
python在CMD界面读取excel所有数据的示例
Sep 28 Python
如何用python实现一个HTTP连接池
Jan 14 Python
Python获取百度热搜的完整代码
Apr 07 Python
详解Python内置模块Collections
Mar 22 Python
Django框架中模型的用法
Jun 10 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
PHP文本操作类
2006/11/25 PHP
珊瑚虫IP库浅析
2007/02/15 PHP
[原创]PHP实现生成vcf vcard文件功能类定义与使用方法详解【附demo源码下载】
2017/09/02 PHP
JavaScript 事件记录使用说明
2009/10/20 Javascript
js或者jquery判断图片是否加载完成实现代码
2013/03/20 Javascript
分享我的jquery实现下拉菜单心的
2015/11/29 Javascript
基于jquery实现鼠标左右拖动滑块滑动附源码下载
2015/12/23 Javascript
socket.io学习教程之深入学习篇(三)
2017/04/29 Javascript
React Native 截屏组件的示例代码
2017/12/06 Javascript
Angular实现搜索框及价格上下限功能
2018/01/19 Javascript
JS实现为动态创建的元素添加事件操作示例
2018/03/17 Javascript
jquery操作select常见方法大全【7种情况】
2019/05/28 jQuery
微信小程序表单验证插件WxValidate的二次封装功能(终极版)
2019/09/03 Javascript
vue3 源码解读之 time slicing的使用方法
2019/10/31 Javascript
vue-router重写push方法,解决相同路径跳转报错问题
2020/08/07 Javascript
javascript实现简易计算器功能
2020/09/23 Javascript
[47:46]完美世界DOTA2联赛 Magma vs GXR 第三场 11.07
2020/11/10 DOTA
Python实现的递归神经网络简单示例
2017/08/11 Python
python实现监控阿里云账户余额功能
2019/12/16 Python
快速解决Django关闭Debug模式无法加载media图片与static静态文件
2020/04/07 Python
keras做CNN的训练误差loss的下降操作
2020/06/22 Python
html5 分层屏幕适配的方法
2018/03/16 HTML / CSS
处理HTML5新标签的浏览器兼容版问题
2017/03/13 HTML / CSS
法国票务网站:Ticketmaster法国
2018/07/09 全球购物
什么是.net的Remoting技术
2016/07/08 面试题
网络工程与软件技术毕业生自荐信
2013/09/24 职场文书
学校食堂食品安全责任书
2014/07/28 职场文书
安全保卫工作竞聘材料
2014/08/25 职场文书
女生抽烟检讨书
2014/10/05 职场文书
投标单位介绍信
2015/05/05 职场文书
食品药品安全责任书
2015/05/11 职场文书
婚庆司仪开场白
2015/05/29 职场文书
导游词之河姆渡遗址博物馆
2019/10/10 职场文书
pytorch 中nn.Dropout的使用说明
2021/05/20 Python
详解Redis复制原理
2021/06/04 Redis
MyBatis-Plus 批量插入数据的操作方法
2021/09/25 Java/Android