python中使用多继承问题和super()内置函数的使用

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
  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值