在Python里面,如果你使用上Qt,SQLAlchemy,Twisted之类各种大型类库时候,有时候多重继承Multiple Inheritance是个简单的解决方法,但是多重继承的复杂性总容易造成误解和疑惑。

一般“常识”说,使用super访问父类的属性/方法,这种说法在多重继承里面是不成立的,多重继承的类并没有父类的概念(There is no superclass in a MI world)。类似的博客在过去几年被人写了无数遍了,因为过去版本里面python官方文档对super的解释非常有限而且有误导解释,直到2.6以后的文档,才详细说明了super在单继承和多继承的两种不同工作方式。当时苦逼的程序员甚至不得不去翻看Python源码才搞清楚是什么回事。以致几年来很多人对python的多重继承保持怀疑态度。

Python多重继承使用Method Resolution Order的动态算法来解决一个方法名的调用顺序,mro其实说来简单,就是一个深度优先的继承列表,很易理解,但随之来的是遇到互不相同的构造器__init__参数的问题。

Codepad运行结果:

class A(object):

def __init__(self, arg1):

print "init func in A, with arg1 '%s'" % arg1

super(A, self).__init__()

class B(object):

def __init__(self, arg1, arg2):

print "init func in B, with arg1'%s', arg2 '%s'" % (arg1, arg2)

super(B, self).__init__(arg1)

class C(B, A):

def __init__(self, arg1, arg2):

print "init func in C, with arg1'%s', arg2 '%s'" % (arg1, arg2)

super(C, self).__init__(arg1, arg2)

print C.__mro__

c = C("C's arg1", "C's arg2")

执行结果:

init func in C, with arg1'C's arg1', arg2 'C's arg2'

init func in B, with arg1'C's arg1', arg2 'C's arg2'

init func in A, with arg1 'C's arg1'

(, , , )

可见几个类的构造器的执行顺序正是mro列表的顺序。重点是多重继承的各个类的构造器__init__之所以能够执行,是因为每个构造器里面都有一句super(),这个super完成mro列表中下一个类的构造器的调用。

这个事实听起来似乎很自然,但看代码,B的构造器还得必须知道A的构造器的参数?B需要知道自己将会被C同时继承A,并且调用A的构造?!!很荒谬,但不幸的这是mro的特点。代码是可以这么写,但不应该,为另一个不知道什么时候会被一起继承的类特地地写代码,跟面对对象设计的解耦原则相违背。How

在mro方式的基础上,这个问题是不可能有效解决的,只能避免。概括起来大概有这么 两种方式。

1.使用传统类的方式,显式调用被继承类的构造器,避开super的mro自动化工作。

Codepad 看运行效果:

class A(object):

def __init__(self, arg1):

print "init func in A, with arg1 '%s'" % arg1

class B(object):

def __init__(self, arg1, arg2):

print "init func in B, with arg1'%s', arg2 '%s'" % (arg1, arg2)

class C(A, B):

def __init__(self, arg1, arg2):

print "init func in C, with arg1'%s', arg2 '%s'" % (arg1, arg2)

#super(C, self).__init__(arg1) #这两行

A.__init__(self, arg1) #等价

B.__init__(self, arg1, arg2)

print C.__mro__

c = C("C's arg1", "C's arg2")

注意 C继承A,B的顺序已经改变。

要排除一个容易产生的误解。Python文档里面的super有个很显著的Note:super() only works for new-style classes. super只适用于新类。但新类并不必须使用super。

直接调用被继承类的__init__作为unbound方法调用,需要指定一个实例,如self作为参数,依次调用各个被继承类。缺点是若果这几个被继承类也在构造方法里面使用这样调用了同一个上级被继承类,会出现“爷爷类”的构造方法被调用多次的情况。

如果一定使用super,要注意继承列表的顺序。super(TYPE, self).method调用的是mro列表中第一个,也即继承列表第一个类的方法。

PyQt里面的类内部一般(未细究)都使用__init__的方式来初始化代码,因而很多PyQt的例子代码都是使用QtGui.QMainWindow.__init__(self)这样的代码来初始化。当然在单继承时候和super的写法是等价的,但最好使用统一的原则:

一个简单好记的原则:

如果”被继承类”都使用__init__,”继承类”就使用__init__来初始化;

如果”被继承类”都使用super,”继承类”就使用super来初始化;

2.使用Composition / Association Pattern的设计模式(即’Is-A’转换成’Has-A’)来实现相同功能,避免多重继承。

这个方法听起来未免有点让人不快(破坏了原有设计思维),但实际上很可能这是更好的方式,更清晰的代码,尤其是要继承的类里面混合了使用super,__init__两种初始化方式的时候。;

玩蛇网文章,转载请注明出处和文章网址:https://www.iplaypy.com/jinjie/jj5808.html

相关文章 Recommend

python 构造函数继承_Python多重继承的异构构造器相关推荐

  1. python多继承_python作用域和多继承

    python作用域 python无块级作用域 看c语言代码: #include intmain() {if(2 > 0) {int i = 0; } printf("i = %d&qu ...

  2. python类方法继承_python类的继承

    一.概述 面向对象编程 (OOP) 语言的一个主要功能就是"继承".继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展. 通过继承 ...

  3. python多继承顺序_Python多重继承方法解析顺序(MRO构建算法)

    分界 python的MRO算法有新旧两种,但并不是以python2和python3为界,具体的分隔为:在python2中如果定义类的时候没有指定父类是object,即定义为 class A: pass ...

  4. python单例模式继承_Python四种实现单例模式的方法

    在这之前,先了解super()和__new__()方法 super()方法: 返回一个父类或兄弟类类型的代理对象,让你能够调用一些从继承过来的方法. 它有两个典型作用: a. 在单继承的类层次结构中, ...

  5. Python 类继承与多重继承

    python中新定义一个类称为子类,被继承的类称为父类:子类继承父类后就拥有了父类的所有特性. #语法格式 class 子类名(父类名):pass 如下:定义了Person类,一个Student类,但 ...

  6. python怎么继承_Python: 如何继承str/string?

    想搞一个对象继承自str,然后存一些额外信息用来标识这个字符串,然后理所当然地重写了__init__发现跪了: class newstring(str): def __init__(self, val ...

  7. python编程语言继承_python应用:学习笔记(Python继承)

    学习笔记(Python继承)Python是一种解释型脚本语言,可以应用于以下领域: web 和 Internet开发 科学计算和统计 人工智能 教育 桌面界面开发 后端开发 网络爬虫 有几种叫法(父类 ...

  8. python类变量继承_python 类的成员及继承

    1. @staticmethod 静态方法 静态方法不能访问实例变量和类变量,除了身处类里面,所以只能通过类调用以外,它其实和类没有什么关系.如果想要用它访问实例变量或类变量,需要把实例和类传递给函数 ...

  9. python面向对象继承_Python 面向对象 --- 继承

    目标 单继承 多继承 面向对象三大特性 1,封装 根据 职责 将 属性 和 方法 封装 到以抽象的 类 中 2,继承 实现代码的重用,相同的代码不需要重复的缩写 3,多态 不同的对象调用相同的方法,产 ...

最新文章

  1. 我所理解的Java NIO
  2. 判断 小程序 是否 滚动到页面底部 scrolltolower_微信小程序长列表性能优化——recycle-view
  3. PHP 接收 UDP包_UDP详解(广播,组播)(转)
  4. python合并表格矩阵并排序_在Python中,将多个列的列表排列成一个矩阵
  5. svc的参考文献_WCF服务三:svc文件详解
  6. Android NDK开发:打包so库及jar包供他人使用
  7. SqlSever2005 一千万条以上记录分页数据库优化经验总结【索引优化 + 代码优化】一周搞定...
  8. 还在担心找不到驱动程序吗?driveridentifier三步帮你解决所有
  9. ABAP--新语法--New Keyword in ABAP--第四天--CORRESPONDING MOVE-CORRESPONDING(DEEP) REDUCE
  10. html文本转成二进制,肿么把文本文件转换成二进制bin文件
  11. 让AI简单且强大:深度学习引擎OneFlow技术实践
  12. 浅谈DM数据库优化常识
  13. 歪门邪道之解决首屏图片加载闪烁问题
  14. 一本通1375:骑马修栅栏(fence)
  15. 一年外包经验入职字节
  16. python判断密码是否正确_python密码判断是否符合要求的方法
  17. 【消息】“莓果儿”QQ群
  18. 使用opencv直接打开云钥GigE网络工业相机
  19. java 正则表达式可以改变么_Java中慎用正则表达式!代码性能影响?
  20. 【算法】-- LintCode经典算法题理解动态规划

热门文章

  1. iphone固件降级_iPhone无法开机怎么办?三种快速维修方法
  2. ruby .each_Ruby中带有示例的Array.each方法
  3. ruby hash添加数据_如何在Ruby中向Hash添加元素?
  4. Java Object Class boolean equals(Object o)方法与示例
  5. Redis 是如何执行的?
  6. 面试官:聊一下你对MySQL索引的理解?
  7. linux——进程(创建、终止、等待、替换)
  8. mysql6.10,MySQL经典50题-第6-10题
  9. keepalived高可用+nginx负载均衡
  10. 三层加过的注释java_spring框架中三层架构相关的注解