Python的Mixins机制
大多数面向对象语言都不支持多重继承,因为这会导致菱形问题, 而 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机制相关推荐
- 深入探讨Python的import机制:实现远程导入模块 | CSDN博文精选
来源 | Python编程时光(ID:Python-Time) 所谓的模块导入,是指在一个模块中使用另一个模块的代码的操作,它有利于代码的复用. 也许你看到这个标题,会说我怎么会发这么基础的文章? 与 ...
- 关于R和Python的安全机制
关于R和Python的安全机制 对于Python: >>> x = [1,2,3,4] >>> y = x >>> x[0] = 100 > ...
- python 释放变量所指向的内存_通俗易懂的Python垃圾回收机制及内存管理
Python垃圾回收机制及内存管理 内存管理: 先定义一个变量 name='wxl' 那么python会在内存中开辟一小块区域存放"wxl",此时变量的值是我们真正想要存储的,wx ...
- python是不是特别垃圾-python垃圾回收机制
python中有自动内存回收机制,一般情况不需要程序员来处理,面试时被大佬问到了,记录一下.没有画图,推荐读参考的第一篇博文 gc方式1:引用计数 若此对象无其他对象引用,则立马回收掉 优点:简单.实 ...
- python是不是特别垃圾-谈谈python垃圾回收机制
什么是垃圾回收机制? 首先,咱先来解释名词,垃圾回收是不是就是将没用的,废弃的东西回收起来. 在坐的各位都没有女朋友对吧,那难以想象你们的房间会是一个什么样子,可能会有很多垃圾,很凌乱,自己也不收拾. ...
- python是不是特别垃圾-深度解析Python垃圾回收机制(超级详细)
我们知道,目前的计算机都采用的是图灵机架构,其本质就是用一条无限长的纸带,对应今天的存储器.随后在工程学的推演中,逐渐出现了寄存器.易失性存储器(内存)以及永久性存储器(硬盘)等产品.由于不同的存储器 ...
- python垃圾回收离职_谈谈python垃圾回收机制
什么是垃圾回收机制? 首先,咱先来解释名词,垃圾回收是不是就是将没用的,废弃的东西回收起来. 在坐的各位都没有女朋友对吧,那难以想象你们的房间会是一个什么样子,可能会有很多垃圾,很凌乱,自己也不收拾. ...
- Python线程同步机制: Locks, RLocks, Semaphores, Condition
为什么80%的码农都做不了架构师?>>> 翻译自Laurent Luce的博客 原文名称:Python threads synchronization: Locks, RLoc ...
- Python虚拟机类机制之descriptor(三)
从slot到descriptor 在Python虚拟机类机制之填充tp_dict(二)这一章的末尾,我们介绍了slot,slot包含了很多关于一个操作的信息,但是很可惜,在tp_dict中,与__ge ...
最新文章
- Redis源码剖析(十二)有序集合跳表实现
- 【1】C++语法与数据结构之C语言学生管理系统转C++学生管理系统
- HTML5清除2个div标签的空白,DIV标签里面IMG图片下方留有空白怎么办
- 测试开发——搭建一个简单 web服务(flask框架基础)项目实战
- linux 运行springboot 项目 (后台运行,并且打印实时日志)
- 增加批量修改成本价格,配合后台管理增加成本价和毛利润统计
- Spring依赖注入流程【完整版】(populateBean方法内部执行流程)
- c语言试题 函数选择,(C语言函数章节选择题.doc
- 单片机c语言如何精确延时,单片机C语言精确延时值的计算
- mysql导入shapefile
- html 嵌入word 插件,利用VenoBox插件在网页中悬浮显示word文档
- 每日一词20190306——经纬度(longitude and latitude)
- python 取整求余函数
- EasyExcel导出Excel 自定义 表头颜色
- 访问WebServcie遇到配额不足的时候,请增加配额
- DIY自制STC单片机开发板
- 关闭Linux防火墙
- fpga驱动rgb液晶屏_用FPGA设计LCD 转 VGA 其实vga和lcd驱动 非常类似
- 各个级别的教师资格证分别可以教什么阶段
- git提交代码时出现错误:error : unpack failed : error Missing commit XXX,
热门文章
- Lesson3 Shader着色器
- Android布局文件的布局方式
- python的日志简单使用
- 广州的11个辖区_广州“受欢迎”的2个区,相距仅20公里,若“合并”将超黄埔区...
- 电脑模拟器哪个好_《英雄聯盟:激鬥峽谷》电脑版哪个安卓模拟器好用?《英雄聯盟:激鬥峽谷》手游电脑版怎么玩...
- 【ABAP】SAP供应商自定义决裁生成实现
- 【实用】ALV 清单右击隐藏列失效的处理
- 【已修正】SAP中各个环境的简介
- 【PP操作手册】创建公司间交易采购订单
- 我该拿什么拯救你,我的CSDN