python多继承和混入类:通俗易懂

1 篇文章 0 订阅
1 篇文章 0 订阅

一、单继承

  1. python中的继承,是可以继承父类所有方法,但是当我们在子类中写__ init__()方法的时候,相当于覆盖了父类的__init__()方法,若想要调用父类的__init__(),可以使用super().__ init__()
class A:
    def __init__(self,a):
        self.a = a
    
    def spam(self):
        print('A.spam')
        
class B(A):
    def __init__(self,a,b):
        self.b = b
        super().__init__(a)
    
    def spam(self):
        print('B.spam')
        super().spam()

b = B(1,2)
b.spam()

# 输出结果
# B.spam
# A.spam

二、多继承

  1. 在python中,处理多继承的方式非常复杂,其中有两个重要的概念,MRO数组,C3算法。
  2. C3算法是为了保证多继承中所有父类都只被实例化一次,因为python在实例化子类的时候首先会实例化父类,python解释器为用这个算法,把该类的所有父类的实例化顺序加入到一个MRO数组里。
  3. 而super()的使用就和这个密切相关。
class Person:
    def __init__(self):
        print('Person.__init__')

class Son1(Person):
    def __init__(self):
        super().__init__()
        print('Son1.__init__')

class Son2(Person):
    def __init__(self):
        super().__init__()
        print('Son2.__init__')

class GrandSon(Son1,Son2):
    def __init__(self):
        super().__init__()  # Only one call to super() here
        print('GrandSon.__init__')

g = GrandSon()
print(GrandSon.__mro__)

# 输出结果
# Person.__init__
# Son2.__init__
# Son1.__init__
# GrandSon.__init__
# (<class '__main__.GrandSon'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Person'>, <class 'object'>)

以上代码大概的继承方式就是这样
在这里插入图片描述

  • 这里大家可以发现,若按照我们之前的理解是不是有点不太对,super()不是调用父类的方法么?

我们用GrandSon.__mro__输出了它所继承的类,super()的真实含义,其实就是在mro数组中,找super()所在的类,之后执行后面的类的方法。

创建GrandSon的对象的时候,我们调用了GrandSon的init()方法,第一句话就是super().init(),那就在mro数组里找GrandSon之后的类,也就是Son1,接着运行Son1的init方法,Son1的init方法第一句又是一个super(),那么就会在mro数组里找本类,也就是Son1类,找到Son1类,执行Son1类之后的Son2类的super()方法。

只不过单继承的mro数组里只有3个类罢了,本类,父类,Object,那么本类之后就是父类。
我们也可以指定到底调用谁之后的类,super(obj,self),这就检测的是obj之后的一个类,但是默认是本类之后的。

class A:
    def sapm(self):
        print('A.sapm')
        super().sapm()
        
class B:
    def sapm(self):
        print('B.sapm')
        
class C(A,B):
    pass
        
c = C()
c.sapm()
# 输出结果
# A.spam
# B.spam

分析一下这个代码,按照我们刚才的思想,次数的mro数组的内容应该是
C类,A类,B类
调用c对象的sapm()方法,但是C类中没有,就会自动去C之后的A对象去找,运行A类中的sapm()方法最后发现还有一个super,并且这个super是在A类中,就去找A类之后的B类,运行B类中的sapm()方法。

三、混入类

  1. 混入类本质上就是一个代码片段,是用来增强"兄弟"类中的同名函数,达到可拔插的效果。
  2. 例如我们要想一个自定义容器。
class LoggedMappingMixin():
    
    def __getitem__(self,key):
        print('获取{}'.format(key),end = ' ')
        return super().__getitem__(key)
    
    def __setitem__(self,key,value):
        print('加入了键值对 {}:{}'.format(key,value))
        super().__setitem__(key,value)
        
    def __delitem__(self,key):
        print('删除了{}'.format(key))
        super().__delitem__(key)
        
class Dict(LoggedMappingMixin,dict):
    pass

dict1 = Dict()
dict1['张三'] = '23'
print(dict1['张三'])
del dict1['张三']

# 输出结果
# 加入了键值对 张三:23
# 获取张三 23
# 删除了张三

这个就明显是强化之后的dict,在获取,添加,删除值的时候都有额外的打印。
由于在MRO中,dict在LoggedMappingMixin之后,所有LoggedMappingMixin调用super会直接调用dict里面的方法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

若能绽放光丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值