python--基础知识点--super和多继承

一、super
1、概念

super:super() 是一个内建函数,用于调用父类的方法。它的一般语法是 super([type[, object-or-type]])。

当不传递参数时,super() 返回一个表示当前类的父类的 super 对象。通过这个对象,你可以调用父类中的方法。
当传递两个参数时,super(type, obj) 会返回一个基于 type 类的 obj 实例的父类的 super 对象。这样可以在子类中调用父类中的方法,并传递正确的实例参数。
super() 主要用于在子类中调用父类的方法,特别是在多继承的情况下,它能够确保方法按照方法解析顺序(MRO)的顺序被调用,避免了由于多继承带来的不确定性。

2、原型

super([type1][, object-or-type2])

3、参数说明

type1:指委托类
object-or-type2:当该参数为object时必须满足isinstance(object, type1) == True:当该参数为type2时,必须满足issubclass(type2, type1) == True。

使用super时可以直接省略掉参数写为super(),因为解释器在执行时会自动添加相应的参数。

4、原理

目前能力有限,还写不出一个功能类似super()的代理类。

此处只是为了用python代码说明super内部实现的逻辑,并不是真实的super相关代码

def super(type1, obj_type2):
    obj_type2 = obj_type2
    if isinstance(obj_type2, type1):
        mro_list = obj_type2.__class__.mro()
    elif issubclass(obj_type2, type1):
        mro_list = obj_type2.mro()
    else:
        print("参数有误!!!")
        raise Exception
    next_class = mro_list[mro_list.index(type1) + 1]
    return next_class

在首次调用时,MRO就已经被确定,是object所属类(即C)的MRO或type2所对应的MRO,因此type1参数的作用就是从已确定的MRO中找到位于其后紧邻的类,作为再次调用super()时查找该方法的下一个类。

5、要点:
  • super()使用的时候需要传递两个参数,在类中可以省略不写,我们使用super()来找父类或者兄弟类的方法;
  • super()是根据第二个参数来计算MRO,根据顺序查找第一个参数类后的方法。
  • super()第二个参数是类,得到的方法是函数,使用时要传self参数。第二个参数是对象,得到的是绑定方法,不需要再传self参数。

给使用super()的一些建议

  • super()调用的方法要存在;
  • 传递参数的时候,尽量使用*args 与**kwargs;
  • 父类中的一些特性,比如【】、重写了__getattr__,super对象是不能使用的。
  • super()第二个参数传的是类的时候,建议调用父类的类方法和静态方法。
二、多继承
1、多继承

Python虽然语法上支持多继承,但是却不推荐使用多继承,而是推荐使用单继承,这样可以保证编程思路更清晰,也可以避免不必要的麻烦。

当以一个子类有多个直接父类时,该子类会继承得到所有父类的方法,但是如果其中有多个父类包含同名方法会发生什么?此时排在前面的父类中的方法会“遮蔽”后面父类中的方法。

示例:
在这里插入图片描述

class Base:
    def __new__(cls, base):
        print(cls)
        print("Base.__new__")
        return super(Base, cls).__new__(cls)

    def __init__(self, base):
        print("Base.__init__")
        self.base = base
        print(self.base)


class A(Base):
    def __new__(cls, base, a, b):
        """
        __new__此处不仅接收参数base,a, 还须接受参数b因为
        C.__mro__ = (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>)
        python3支持多继承,搜索父类及兄弟类时是按照广度优先搜索遍历,遍历结果也就是C.__mro__从左到右的顺序,
        此处下一个时A的兄弟类B
        """
        print(cls)
        print("A.__new__")
        return super(A, cls).__new__(cls, base, b)

    def __init__(self, base, a, b):
        super(A, self).__init__(base, b)
        print("A.__init__")
        self.a = a
        print(self.a)


class B(Base):
    def __new__(cls, base, b):
        print(cls)
        print("B.__new__")
        return super(B, cls).__new__(cls, base)

    def __init__(self, base, b):
        super(B, self).__init__(base)
        print("B.__init__")
        self.b = b
        print(self.b)


class C(A, B):
    __c_class__ = 4

    def __new__(cls, base, a, b, c):
        print(cls)
        print("C.__new__")
        return super(C, cls).__new__(cls, base, a, b)

    def __init__(self, base, a, b, c):
        super(C, self).__init__(base, a, b)
        print("C.__init__")
        self.c = c
        print(self.c)


print(C.__mro__)
test = C(base=0, a=1, b=2, c=3)
print(test.base, test.a, test.b, test.c)


"""
运行结果:
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>)
<class '__main__.C'>
C.__new__
<class '__main__.C'>
A.__new__
<class '__main__.C'>
B.__new__
<class '__main__.C'>
Base.__new__
Base.__init__
0
B.__init__
2
A.__init__
1
C.__init__
3
0 1 2 3

Process finished with exit code 0
"""
2、多继承协同

示例:

class Minix1:
    """该混合类为header列表末尾添加data1"""

    def get_header(self):
        print('run Minix1.get_header')  # 1
        ctx = super().get_header()      # 2 10
        ctx.append('data1')             # 11
        return ctx                      # 12


class Minix2:
    """该混合类为header列表头部添加data2"""

    def get_header(self):
        print('run Minix2.get_header')  # 3
        ctx = super().get_header()      # 4 7
        ctx.append('data2')             # 8
        return ctx                      # 9


class Header:
    header = []

    def get_header(self):
        print('run Headers.get_header')            # 5
        return self.header if self.header else []  # 6


class Final(Minix1, Minix2, Header):

    def get_header(self):
        return super().get_header()


print(Final.mro())
header = Final().get_header()
print(header)




"""
[<class '__main__.Final'>, <class '__main__.Minix1'>, <class '__main__.Minix2'>, <class '__main__.Header'>, <class 'object'>]
run Minix1.get_header
run Minix2.get_header
run Headers.get_header
['data2', 'data1']

Process finished with exit code 0
"""

看来,运行得很成功,我们实现了多继承协同工作的目标,通过混合不同个类,来模块化地快速得到想要的header属性。而这种工作方法,通过单纯的重写某个方法根本无法实现的,因为重写任何方法,它会在MRO列表中找到最优先(也就是最靠前)的拥有同名方法的类,然后调用该方法,并且终止检索,某项属性仅仅会被一个方法所影响。

这个特性,在Django的CBV中有相当程度的应用。

[参考博客]
https://www.cnblogs.com/tizer/p/11142475.html
https://www.cnblogs.com/miyauchi-renge/p/10923127.html
https://www.cnblogs.com/yuanyongqiang/articles/9392765.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值