鱼C论坛

 找回密码
 立即注册
查看: 1601|回复: 3

[技术交流] 发个帖子,活跃一下,关于Spuer函数的个人笔记。

[复制链接]
发表于 2020-2-22 04:07:51 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 Stubborn 于 2020-2-22 04:10 编辑

super() 函数是用于调用父类(超类)的一个方法。super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。

super()官方介绍:V3.8

官方介绍就不抄过来了,很多链接,容易被禁

个人理解:
将方法调用委托给 *type* 的父类或兄弟类,这个暂时不说,先了解,它怎么取找到,确认调用父类的方法。官方文档说,可以使用*object-or-type*的 [`__mro__`]属性,来确定它的搜索顺序。
class A: pass                                                                             
class B: pass                                                                             
class C(A, B): pass                                                                       
print(C.mro())                                                                            
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]    
class D:pass                                                                              
class E(C, D):pass                                                                        
print(E.mro())                                                                            
# [<class '.E'>, <class '.C'>, <class '.A'>, <class '.B'>, <class '.D'>, <class 'object'>]

结合代码<*E→C→A→B→D*>可以很容易的看出,先检查自身,而后从继承的父类或者兄弟类(A和B),从左到右检查,父类如果还存在继承,优先被检查。


**一个类的 [`__mro__`](https://docs.python.org/zh-cn/3. ... .html#class.__mro__) 属性的三个准则:**

- 子类会先于父类被检查
- 多个父类会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类

委托给父类可能都用过,那么委托兄弟类是什么意思呢?
class A:
    def spam(self):
        print("A.spam")
        super().spam()

class B:
    def spam(self):
        print("B.spam")


class C(A, B):
    def spam(self):
        print("C.sapm")
        super().spam()
"""
C.sapm
A.spam
B.spam
"""

如代码示例,A类并没有父类,但是在继承结构中,B类和A类互为兄弟类。所以`super()`在A中调用的时候,最终却调用其兄弟的同名方法,这就是之前说的,*`super`函数返回一个委托类`type`的父类或者兄弟类方法调用的代理对象*。

注意

注意上面说的搜索顺序,如上C的mro顺序是[C→A→B→object],type为A的时候,则 `super()` 将会搜索 `B→object`,也就是说,同为兄弟类,在B中使用`super().spam()`,那么`super()`只会搜索`object`。可能说的有点绕口,说简白点,在如上的继承结构中,A可以委派给B兄弟类,但是B不能委派给A兄弟类,因为在mro中,super已经搜索不到spam()方法。

然后说下,为什么A可以委派给兄弟B类呢?

`super()`是`super(type, obj)`的简写,在调用`super()`时,`type`参数传入的是当前的类,而`obj`参数则是默认传入当前的实例对象,在`super()`的后续调用中,`obj`一直未变,而实际传入的`class`是动态变化,不过,在首次调用时,MRO就已经被确定,是`obj`所属类(即C)的MRO,因此`class`参数的作用就是从已确定的MRO中找到位于其后紧邻的类,作为再次调用`super()`时查找该方法的下一个类。
即,`super`函数这一部分的核心逻辑应该为
def super(class, obj):
    mro_list = obj.__class__.mro()
    next_parent_class = mro_list[mro_list.index(class)+1]
    return next_parent_class

这就是为什么必须保证`isinstance(obj, type)`为`True`的原因,如果不是,那么可能`type`就不存在于`obj.__class__`的MRO列表中,该算法就无法正确找到下一个应当被查找的类。

因此,如果我们在某个类的父类中按照其MRO顺序,每个父类都写一个同名方法,同时每个该方法中都继续调用`super()`,直到在MRO列表`object`之前的最后一个类的同名方法中不再调用`super()`,那么在调用该方法时,会在各个父类中按照MRO列表的顺序依次被调用,这个过程中存在数据的传递,代表它们之间可以**共享**某些数据,这就实现了多继承协同工作。

而这种工作方式,通过重写方法是根本无法实现的。

案例:

我们试图达到如下目的:

一个类`Final`继承`Header`以获得属性`header`
同时我们通过混合其他类来快捷地修饰`header`属性,例如继承类`CookieMinix`为`header`添加`cookie`,而继承`UserAgentMinix`为`header`添加`user-agent`。注意,因为这些操作并不冲突,这些行为都不该相互覆盖。
class CookieMinix:

    def get_header(self):
        print('Add cookie')
        ctx = super().get_header()
        ctx["cookie"] = "cookies"
        return ctx


class UserAgentMinix:

    def get_header(self):
        print('add user-agent')
        ctx = super().get_header()
        ctx["User-Agent"] = "浏览器头"
        return ctx


class Header:
    headers = {}

    def get_header(self):
        print('create headers dict')
        return self.headers if self.headers else {}


class Final(CookieMinix, UserAgentMinix, Header):

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


header = Final().get_header()

当然,我们可以定义更多的混合类,并从中选取所需的类来快速得到想要的`header`属性, 在这个例子中,这两个混合类已经足够说明问题。我们实现了多继承协同工作的目标,通过混合不同个类,来模块化地快速得到想要的`header`属性。
而这种工作方法,通过单纯的重写某个方法根本无法实现的,因为重写任何方法,它会在MRO列表中找到最优先(也就是最靠前)的拥有同名方法的类,然后调用该方法,并且终止检索,某项属性仅仅会被**一个**方法所影响。

评分

参与人数 1荣誉 +2 鱼币 +2 收起 理由
hrp + 2 + 2

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-2-22 09:17:25 | 显示全部楼层
标题有问题
是Super,不是Spuer
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-2-22 09:58:50 From FishC Mobile | 显示全部楼层
点赞
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-2-22 11:05:07 From FishC Mobile | 显示全部楼层
这个可以有
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-24 20:51

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表