python中使用多继承问题和super()内置函数的使用
1、python中使用多继承问题
python中使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承,也叫菱形继承问题)等
1.1、MRO简介:
MRO即方法解析顺序(method resolution order),用于判断子类调用的属性来自于哪个父类。在Python2.3之前,MRO是基于深度优先算法的,自2.3开始使用C3算法,定义类时需要继承object,这样的类称为新式类,否则为旧式类
从图中可以看出,旧式类查找属性时是深度优先搜索,新式类则是广度优先搜索
C3算法最早被提出是用于Lisp的,应用在Python中是为了解决原来基于深度优先搜索算法不满足本地优先级,和单调性的问题。本地优先级:指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。
单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序
1.2、例子:
class X(object):
def f(self):
print 'x'
class A(X):
def f(self):
print 'a'
def extral(self):
print 'extral a'
class B(X):
def f(self):
print 'b'
def extral(self):
print 'extral b'
class C(A,B,X):
'''
如果是class C(X,B,A): class C(B,A,X): 则会报如下错误:
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases X, B, A
'''
def f(self):
super(C, self).f()
print 'c'
print "调用顺序 ", C.mro()
c = C()
c.f() # 指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类
c.extral() # 指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类
根据广度搜索原则最先搜索到A,所以结果很明显,如下所示:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /Users/a6/Downloads/PycharmProjects/Attempt_new/chat_mes_dm_sparkSql/test_use_super.py
调用顺序 [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.X'>, <type 'object'>]
a
c
extral a
Process finished with exit code 0
类C没有extral函数,调用的是子类的该函数。这种类的部分行为由父类来提供的行为,叫做抽象超类.
2、super函数介绍:
2.1 描述
super() 函数是用于调用父类(超类)的一个方法。super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
2.2 语法
以下是 super() 方法的语法:
super(type[, object-or-type])
参数
type -- 类。
object-or-type -- 类,一般是 self
Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx :
2.3、# 不使用super函数,而直接使用非绑定函数的例子
# -*- coding: utf-8 -*-
# 不使用super函数,而直接使用非绑定函数的例子
class A:
def __init__(self):
print "enter A"
print "leave A"
class B(A):
def __init__(self):
print "enter B"
A.__init__(self) # old method
print "leave B"
b = B()
输出结果:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /Users/a6/Downloads/PycharmProjects/Attempt_new/chat_mes_dm_sparkSql/test_use_super.py
enter B
enter A
leave A
leave B
Process finished with exit code 0
2.4、# 使用super()函数的例子
# -*- coding: utf-8 -*-
# 使用super()函数的例子
class A(object): # A must be new-style class
def __init__(self):
print "enter A"
print "leave A"
class C(A): # A must be new-style class
def __init__(self):
print "enter C"
super(C,self).__init__()
print "leave C"
class B(C,A):
def __init__(self):
print "enter B"
super(B, self).__init__() # new method 只适用于新式类,定义形如class A(object)为新式类,形如class A()为经典(老式类)定义
print "leave B"
c=C()
print "**********"
b = B()
输出结果:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /Users/a6/Downloads/PycharmProjects/Attempt_new/chat_mes_dm_sparkSql/test_use_super.py
enter C
enter A
leave A
leave C
**********
enter B
enter C
enter A
leave A
leave C
leave B
Process finished with exit code 0
2.5、例子:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class FooParent(object):
def __init__(self):
self.parent = 'I\'m the parent.'
print ('Parent')
self.child_has="FooParent has variable"
def bar(self, message):
print ("%s from Parent" % message)
class FooChild(FooParent):
def __init__(self):
# super(FooChild,self) 首先找到 FooChild 的父类(就是类 FooParent),然后把类B的对象 FooChild 转换为类 FooParent 的对象
super(FooChild, self).__init__()
print ('Child')
self.child_has="child_has variable"
def bar(self, message):
print ('Child bar fuction')
super(FooChild, self).bar(message)
print (self.parent) # 子类没有,就向父类查找
print self.child_has # 首先查找子类,子类有,则输出子类的内容,子类没有,则按照MRO顺序查找其父类
if __name__ == '__main__':
fooChild = FooChild()
print "************"
fooChild.bar('HelloWorld')
输出结果:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /Users/a6/Downloads/PycharmProjects/Attempt_new/chat_mes_dm_sparkSql/test_use_super.py
Parent
Child
************
Child bar fuction
HelloWorld from Parent
I'm the parent.
child_has variable
Process finished with exit code 0