大多数面向对象语言都不支持多重继承,因为这会导致菱形问题, 而 Python 虽然形式上支持多重继承,但其实现机制却是利用 mixin,从而有效 地避免了菱形问题。

一、什么是 mixin

Mixin本意是混入,程序中用来将不同功能(functionality)组合起来,从而为 类提供多种特性。而虽然继承(inheritance)也可以实现多种功能,但继承一般 有从属关系,即子类通常是父类更加具体的类。而 mixin 则更多的是功能上的 组合,因而相当于是接口(带实现的接口)。

好比是联想电脑与电脑之间是继承关系,因而联想电脑具备电脑的各种功能;而 联想电脑与键盘之间则是 mixin 关系,同样也具备键盘的各种功能。

一般编程语言都不允许多重继承,主要是为了避免菱形问题,即两个父 类如果有共同的祖父类,但对祖父类相同部分做了不同的修改,则这个类再继承 两个父类就会产生冲突。

类似于 git 版本控制中,如果两个人对同一段代码做了不同的修改,则合并时 就需要手动解决冲突。编程语言如果碰到 diamond problem 时依赖程序员决定 用哪个父类的特性,就会变得非常复杂而且容易产生歧义。

从上面分析可以看出其实单从功能上来说,完全可以用 mixin 取代继承,从而 可以不要类这个概念。最近几年新出的编程语言 Rust 和Go里面就没有类 (class)以及继承,但并不影响代码复用,它们也正是利用 mixin 这种机制实现 的代码复用,例如 Rust 中用特征(Trait)取代了类和接口。

两种观点其实是两种不同的世界观,目前类与继承的概念则更为流行,而且符合 人们对事物的认知:人们对白猫、黑猫、花猫观察后更容易抽象出猫的概念,而 不是将这些事物作为无规律的组合去看待。

二、Python 中的 mixin

理解了 mixin 概念之后,再将其运用到 Python 中,理解(形式上)多重继承 就会容易许多。python 对于 mixin 命名方式一般以 MixIn, able, ible 为后缀

由于 mixin 是组合,因而是做加法,为已有的类添加新功能,而不像继承一样 下一级会覆盖上一级相同的属性或方法,但在某些方面仍然表现得与继承一样, 例如类的实例也是每个 mixin 的实例。mixin 使用不当会导致类的命名空间污 染,所以要尽量避免 mixin 中定义相同方法,对于相同的方法,有时很难区分 实例到底使用的是哪个方法。

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Mixin1(object):def test(self):print("mixin 1")def which_test(self):self.test()class Mixin2(object):def test(self):print("mixin 2")class MyClass1(Mixin1, Mixin2):pass                        # 按从左到右顺序从 mixin 中获取功能并添加到 MyClassclass Myclass2(Mixin1, Mixin2):def test(self):             # 已有 test 方法,因而不会再添加 Mixin1, Mixin2 的 test 方法print("my class 2")c1 = MyClass1()
c1.test()                       # => "mixin 1"
c2 = MyClass2()
c2.test()                       # => "my class 2"
c2.which_test()                 # => "my class 2"
isinstance(c1, Mixin1)          # => True
issubclass(MyClass1, Mixin2)    # => True

Mixin 强调的是功能而不像继承那样包括所有功能和数据域,但利用 mixin 同 样也可以实现代码复用,下面这段代码来自Stack Overflow,当然 functools.total_ordering() 装饰器已经提供相同功能了,这里仅用来说明 mixin 实现代码复用。

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class Comparable(object):def __ne__(self, other):return not (self == other)def __lt__(self, other):return self <= other and (self != other)def __gt__(self, other):return not self <= otherdef __ge__(self, other):return self == other or self > otherclass Integer(Comparable):def __init__(self, i):self.i = iclass Char(Comparable):def __init__(self, c):self.c = c

下面是 Python2 中动态加入 mixin 的方法[fn:1],python3 中已经不支持这种 方法了,python3 可能需要借助 type 等元编程工具实现[fn:2]动态 mixin

def MixIn(pyClass, mixInClass, makeLast=0):if mixInClass not in pyClass.__bases__:if makeLast:pyClass.__bases__ += (mixInClass,)else:pyClass.__bases__ = (mixInClass,) + pyClass.__bases

不过尽管动态 mixin 是可能的,但实际使用中要尽量避免这样做,因为可能会 使所有使用这个 mixin 的实例出现一些不可预知的问题。

三、Python的mixin 和 Ruby的mixin

Matthew J. Morrison提到的例子表明 Python 的 mixin 并不是纯粹意义上的 mixin,还是带有继承的特点。

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
from datetime import datetime, date
import jsonclass Jsonable(object):def date_handler(self, obj):if isinstance(obj, (datetime, date)):return obj.isoformat()def save_json(self, file_name):with open(file_name, 'w') as output:output.write(json.dumps(self.__dict__, default=self.date_handler))class Person(Jsonable):def __init__(self, name, bday):self.name = nameself.bday = bdayif __name__ == '__main__':matt = Person('matt', date(1983, 07, 12))matt.save_json("matt.json")assert issubclass(Person, Jsonable)assert isinstance(matt, Person)assert isinstance(matt, Jsonable)

而 Ruby 的 Mixin 则不带有继承的概念,直接使用 include 引入 mixin。从语 义上讲,的确用 include 描述比 inherit 更准确。

require "json"module Jsonabledef jsonifyjson_data = {}self.instance_variables.each do |v|json_data[v.to_s[1..-1]] = self.instance_variable_get(v)endreturn json_data.to_jsonenddef save_json(file_name)File.open(file_name, 'w') {|f| f.write(self.jsonify) }endendclass Personinclude Jsonabledef initialize(name, bday)@name = name@bday = bdayend
endperson = Person.new('name', '07/12/1983')
person.save_json('ruby.json')
raise "not instance" unless person.instance_of? Person
raise "is instance" if person.instance_of? Jsonable
raise "subclass" if Person.is_a? Jsonable

Python的Mixins机制相关推荐

  1. 深入探讨Python的import机制:实现远程导入模块 | CSDN博文精选

    来源 | Python编程时光(ID:Python-Time) 所谓的模块导入,是指在一个模块中使用另一个模块的代码的操作,它有利于代码的复用. 也许你看到这个标题,会说我怎么会发这么基础的文章? 与 ...

  2. 关于R和Python的安全机制

    关于R和Python的安全机制 对于Python: >>> x = [1,2,3,4] >>> y = x >>> x[0] = 100 > ...

  3. python 释放变量所指向的内存_通俗易懂的Python垃圾回收机制及内存管理

    Python垃圾回收机制及内存管理 内存管理: 先定义一个变量 name='wxl' 那么python会在内存中开辟一小块区域存放"wxl",此时变量的值是我们真正想要存储的,wx ...

  4. python是不是特别垃圾-python垃圾回收机制

    python中有自动内存回收机制,一般情况不需要程序员来处理,面试时被大佬问到了,记录一下.没有画图,推荐读参考的第一篇博文 gc方式1:引用计数 若此对象无其他对象引用,则立马回收掉 优点:简单.实 ...

  5. python是不是特别垃圾-谈谈python垃圾回收机制

    什么是垃圾回收机制? 首先,咱先来解释名词,垃圾回收是不是就是将没用的,废弃的东西回收起来. 在坐的各位都没有女朋友对吧,那难以想象你们的房间会是一个什么样子,可能会有很多垃圾,很凌乱,自己也不收拾. ...

  6. python是不是特别垃圾-深度解析Python垃圾回收机制(超级详细)

    我们知道,目前的计算机都采用的是图灵机架构,其本质就是用一条无限长的纸带,对应今天的存储器.随后在工程学的推演中,逐渐出现了寄存器.易失性存储器(内存)以及永久性存储器(硬盘)等产品.由于不同的存储器 ...

  7. python垃圾回收离职_谈谈python垃圾回收机制

    什么是垃圾回收机制? 首先,咱先来解释名词,垃圾回收是不是就是将没用的,废弃的东西回收起来. 在坐的各位都没有女朋友对吧,那难以想象你们的房间会是一个什么样子,可能会有很多垃圾,很凌乱,自己也不收拾. ...

  8. Python线程同步机制: Locks, RLocks, Semaphores, Condition

    为什么80%的码农都做不了架构师?>>>    翻译自Laurent Luce的博客 原文名称:Python threads synchronization: Locks, RLoc ...

  9. Python虚拟机类机制之descriptor(三)

    从slot到descriptor 在Python虚拟机类机制之填充tp_dict(二)这一章的末尾,我们介绍了slot,slot包含了很多关于一个操作的信息,但是很可惜,在tp_dict中,与__ge ...

最新文章

  1. Redis源码剖析(十二)有序集合跳表实现
  2. 【1】C++语法与数据结构之C语言学生管理系统转C++学生管理系统
  3. HTML5清除2个div标签的空白,DIV标签里面IMG图片下方留有空白怎么办
  4. 测试开发——搭建一个简单 web服务(flask框架基础)项目实战
  5. linux 运行springboot 项目 (后台运行,并且打印实时日志)
  6. 增加批量修改成本价格,配合后台管理增加成本价和毛利润统计
  7. Spring依赖注入流程【完整版】(populateBean方法内部执行流程)
  8. c语言试题 函数选择,(C语言函数章节选择题.doc
  9. 单片机c语言如何精确延时,单片机C语言精确延时值的计算
  10. mysql导入shapefile
  11. html 嵌入word 插件,利用VenoBox插件在网页中悬浮显示word文档
  12. 每日一词20190306——经纬度(longitude and latitude)
  13. python 取整求余函数
  14. EasyExcel导出Excel 自定义 表头颜色
  15. 访问WebServcie遇到配额不足的时候,请增加配额
  16. DIY自制STC单片机开发板
  17. 关闭Linux防火墙
  18. fpga驱动rgb液晶屏_用FPGA设计LCD 转 VGA 其实vga和lcd驱动 非常类似
  19. 各个级别的教师资格证分别可以教什么阶段
  20. git提交代码时出现错误:error : unpack failed : error Missing commit XXX,

热门文章

  1. Lesson3 Shader着色器
  2. Android布局文件的布局方式
  3. python的日志简单使用
  4. 广州的11个辖区_广州“受欢迎”的2个区,相距仅20公里,若“合并”将超黄埔区...
  5. 电脑模拟器哪个好_《英雄聯盟:激鬥峽谷》电脑版哪个安卓模拟器好用?《英雄聯盟:激鬥峽谷》手游电脑版怎么玩...
  6. 【ABAP】SAP供应商自定义决裁生成实现
  7. 【实用】ALV 清单右击隐藏列失效的处理
  8. 【已修正】SAP中各个环境的简介
  9. 【PP操作手册】创建公司间交易采购订单
  10. 我该拿什么拯救你,我的CSDN