原文:https://github.com/dengshuan/notes/blob/master/techs/python-mixins.org

https://blog.csdn.net/u012814856/article/details/81355935--------一个例子走近 Python 的 Mixin 类:利用 Python 多继承的魔力

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

什么是 mixin

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

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

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

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

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

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

Python 中的 mixin

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

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

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 中获取功能并添加到 MyClass class 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 实现代码复用。

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 <= other def __ge__(self, other):
return self == other or self > other class Integer(Comparable):
def __init__(self, i):
self.i = i class 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 v.s. Ruby mixin

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

from datetime import datetime, date
import json class 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 = name
self.bday = bday if __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 Jsonable
def jsonify
json_data = {}
self.instance_variables.each do |v|
json_data[v.to_s[1..-1]] = self.instance_variable_get(v)
end
return json_data.to_json
end def save_json(file_name)
File.open(file_name, 'w') {|f| f.write(self.jsonify) }
end end class Person
include Jsonable
def initialize(name, bday)
@name = name
@bday = bday
end
end person = 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. [面向对象之继承应用(在子类派生重用父类功能(super),继承实现原理(继承顺序、菱形问题、继承原理、Mixins机制),组合]

    [面向对象之继承应用(在子类派生重用父类功能(super),继承实现原理(继承顺序.菱形问题.继承原理.Mixins机制),组合] 继承应用 类与类之间的继承指的是什么'是'什么的关系(比如人类,猪类 ...

  2. 面对对象4 Mixins机制 内置方法 反射 异常

    Mixins机制 为什么要有:子类继承父类的时候,可能会碰到需要继承多个父类的情况,那么继承关系也分主类和辅类,既保持主类的功能,也有辅类的功能. 命名方式,我们需要将主类和辅类区分开来,python ...

  3. 【Python&数据结构】 抽象数据类型 Python类机制和异常

    这篇是<数据结构与算法Python语言描述>的笔记,但是大头在Python类机制和面向对象编程的说明上面.我也不知道该放什么分类了..总之之前也没怎么认真接触过基于类而不是独立函数的Pyt ...

  4. Python反射机制理解

    Python反射机制用沛齐老师总结的话说就是:利用字符串的形式去对象(模块)中操作(寻找)成员. getattr(object, name) object代表模块,name代表模块中的属性或成员,该函 ...

  5. 理解Python命名机制

    理解Python命名机制 本文最初发表于恋花蝶的博客(http://blog.csdn.net/lanphaday),欢迎转载,但必须保留此声明且不得用于商业目的.谢谢. 引子 我热情地邀请大家猜测下 ...

  6. Python内部机制-PyObject对象

    PyObject对象机制的基石 学过Python的人应该非常清晰,Python中一切都是对象,全部的对象都有一个共同的基类,对于本篇博文来说,一切皆是对象则是探索Python的对象机制的一个入口点.我 ...

  7. 20191031:Python底层机制

    20191031:Python底层机制 python底层从3个方面来说,分别是: 引用计数机制 垃圾回收机制 内存池机制 引用计数机制 使用引用计数来追踪内存中的对象,所有对象都有引用计数,并且这个引 ...

  8. Python执行机制

    1.4 Python执行机制 Python中IDLE是其自带的集成开发工具(IDE:同时拥有编辑.编译.调试.运行等多种功能的集成工具),并且它也是Python自带的编译器和解释器. 1.4.1 Py ...

  9. python反射机制深入分析

    对编程语言比较熟悉的朋友,应该知道“反射”这个机制.Python作为一门动态语言,当然不会缺少这一重要功能.然而,在网络上却很少见到有详细或者深刻的剖析论文.下面结合一个web路由的实例来阐述pyth ...

随机推荐

  1. create table b1 as select * from b建表锁表测试

    A: create table a1 like a; insert into a1 as select * from a; B: create table b1 as select * from b; ...

  2. WEB版一次选择多个文件进行批量上传(swfupload)的解决方案

    说明:功能完全支持ie和firefox浏览器! 一般的WEB方式文件上传只能使用FileUpload控件进行一个文件一个文件的进行上传,就算是批量上传,也要把文件一个一个的添加到页面,无法如windo ...

  3. hdu 5087 次长升序串的长度

    http://acm.hdu.edu.cn/showproblem.php?pid=5087 求数列次长升序串的长度 还是dp求最长升序串的长度,再开一个数组记录对于dp值的串的个数 最后看一下最长字 ...

  4. hive函数 get_json_object的使用

    hive提供了json的解析函数:get_json_object 使用方法 对于jsonArray(json数组),如person表的xjson字段有数据: [{"name":&q ...

  5. AngularJS config run 及区别和例子

    一.config方法 在模块加载阶段,对模块进行自定义配置 config可以注入$stateProvider, $urlRouterProvider, $controllerProvider, $pr ...

  6. Delphi 内进行音量控制及静音

    unit UMute; interface uses MMSystem, Dialogs; Type   TDeviceName = (Master, Microphone, WaveOut, Syn ...

  7. ASP.NET Web API + Elasticsearch 6.x 快速做个全文搜索

    最近想做个全文搜索,设想用 ASP.NET Web API + Elasticsearch 6.x 来实现. 网上搜了下 Elasticsearch 的资料,大部分是讲 linux 平台下如何用 ja ...

  8. nodejs 环境配置技巧

    环境:Mac OSX 10.10.3 NodeJS:v0.12.2 NodeJs 安装指需要 1.执行 npm install xxxx -g 时 需要执行 sudo npm install xxxx ...

  9. 36_并发编程-multiprocess模块

    仔细说来,multiprocess不是一个模块而是python中一个操作.管理进程的包. 之所以叫multi是取自multiple的多功能的意思,在这个包中几乎包含了和进程有关的所有子模块.由于提供的 ...

  10. 02_python_while循环/格式化输出/逻辑运算

    一. while循环 1.基本形式 while 条件: 循环体 # 判断条件是否为真,如果真,执行代码块.然后再次判断条件是否为真.如果真继续执行代码块...直到条件变成了假.循环退出 ps:死循环 ...