(转)Python Mixins 机制
原文: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 机制的更多相关文章
- [面向对象之继承应用(在子类派生重用父类功能(super),继承实现原理(继承顺序、菱形问题、继承原理、Mixins机制),组合]
[面向对象之继承应用(在子类派生重用父类功能(super),继承实现原理(继承顺序.菱形问题.继承原理.Mixins机制),组合] 继承应用 类与类之间的继承指的是什么'是'什么的关系(比如人类,猪类 ...
- 面对对象4 Mixins机制 内置方法 反射 异常
Mixins机制 为什么要有:子类继承父类的时候,可能会碰到需要继承多个父类的情况,那么继承关系也分主类和辅类,既保持主类的功能,也有辅类的功能. 命名方式,我们需要将主类和辅类区分开来,python ...
- 【Python&数据结构】 抽象数据类型 Python类机制和异常
这篇是<数据结构与算法Python语言描述>的笔记,但是大头在Python类机制和面向对象编程的说明上面.我也不知道该放什么分类了..总之之前也没怎么认真接触过基于类而不是独立函数的Pyt ...
- Python反射机制理解
Python反射机制用沛齐老师总结的话说就是:利用字符串的形式去对象(模块)中操作(寻找)成员. getattr(object, name) object代表模块,name代表模块中的属性或成员,该函 ...
- 理解Python命名机制
理解Python命名机制 本文最初发表于恋花蝶的博客(http://blog.csdn.net/lanphaday),欢迎转载,但必须保留此声明且不得用于商业目的.谢谢. 引子 我热情地邀请大家猜测下 ...
- Python内部机制-PyObject对象
PyObject对象机制的基石 学过Python的人应该非常清晰,Python中一切都是对象,全部的对象都有一个共同的基类,对于本篇博文来说,一切皆是对象则是探索Python的对象机制的一个入口点.我 ...
- 20191031:Python底层机制
20191031:Python底层机制 python底层从3个方面来说,分别是: 引用计数机制 垃圾回收机制 内存池机制 引用计数机制 使用引用计数来追踪内存中的对象,所有对象都有引用计数,并且这个引 ...
- Python执行机制
1.4 Python执行机制 Python中IDLE是其自带的集成开发工具(IDE:同时拥有编辑.编译.调试.运行等多种功能的集成工具),并且它也是Python自带的编译器和解释器. 1.4.1 Py ...
- python反射机制深入分析
对编程语言比较熟悉的朋友,应该知道“反射”这个机制.Python作为一门动态语言,当然不会缺少这一重要功能.然而,在网络上却很少见到有详细或者深刻的剖析论文.下面结合一个web路由的实例来阐述pyth ...
随机推荐
- nginx location配置和rewrite写法
location = / { # 精确匹配 / ,主机名后面不能带任何字符串 [ configuration A ] } location / { # 因为所有的地址都以 / 开头,所以这条规则将匹配 ...
- Web墨卡托坐标与WGS84坐标互转
原文地址:http://bbs.esrichina-bj.cn/ESRI/thread-78245-1-1.html 在WebGIS的开发中经常用到的地图投影为Web墨卡托和WGS84,故歌地图,bi ...
- java的静态内部类
只是一个简单的记录.因为一直排斥java这个东西.java跟c++比是很不错的一个语言,至少内存管理这么麻烦的东西不用操心了.但是和不断崛起的脚本语言比起来,效率差的太多.无论如何做android还是 ...
- Java应用分类
Java应用分类 一.应用程序.指在操作系统上直接运行的,不是浏览器,Java环境用本机的,需要在客户端安装,Java环境可以一起安装. 1.GUI图形界面应用程序 ...
- (转)什么是.NET?什么是CLI?什么是CLR?IL是什么?JIT是什么,它是如何工作的?GC是什么,简述一下GC的工作方式?
转自:http://www.cnblogs.com/haofaner/articles/2288968.html 1:什么是.NET? NET 是 Microsoft 的用以创建 XML Web 服务 ...
- 20145232 韩文浩 《Java程序设计》第8周学习总结
教材学习内容总结 14 NIO与NIO2 NIO使用频道(channel)来衔接数据节点,对数据区的标记提供了clear(),rewind(),flip(),compact()等高级操作. 想要取得c ...
- css3实现卡牌旋转与物体发光效果
效果演示 http://demo.qpdiy.com/hxw/CSS3/rotate+light.html 物体旋转: 卡牌同一位置放2张图片,通过设置3D动画旋转实现 animation: card ...
- docker+phantomjs+haproxy 搭建phantomjs集群
目标: 搭建一个远程的phantomjs服务器,提供高可用服务,支持并发. 原料: 1.docker环境.docker-compose环境 2.phantomjs镜像: docker.io/werni ...
- HDU1853 Cyclic Tour
Cyclic Tour Time Limi ...
- 对java高级程序员有益的十本书
英文原文:http://www.programcreek.com/2013/08/top-books-for-advanced-level-java-developers/ java语言是当今最受欢迎 ...