面向对象super内置函数(转)

super函数用来解决钻石继承。

一、python的继承以及调用父类成员

父类:

class Base(object):

    def __init__(self):
        print("base init.")

普通方法调用父类:

class Leaf(Base):

    def __init__(self):
        Base.__init__(self)
        print("Leaf init.")

super方法调用父类:

class Leaf(Base):

    def __init__(self):
        super(Leaf, self).__init__()
        print("Leaf init.")

二、钻石继承

使用普通方法调用父类,base类会初始化2次。用super解决这个问题。

class Base(object):

    def __init__(self):
        print("Base init")

class Medium1(Base):

    def __init__(self):
        super(Medium1, self).__init__()
        print("Medium1 init")

class Medium2(Base):

    def __init__(self):
        super(Medium2, self).__init__()
        print("Medium2 init")

class Leaf(Medium1, Medium2):

    def __init__(self):
        super(Leaf, self).__init__()
        print("Leaf init")

leaf = Leaf()

三、super工作原理

要理解super的原理,就要先了解mro。mro是method resolution order的缩写,表示了类继承体系中的成员解析顺序。在python中,每个类都有一个mro的类方法。我们来看一下钻石继承中,Leaf类的mro是什么样子的:

print(Leaf.mro())
[<class ‘__main__.Leaf‘>, <class ‘__main__.Medium1‘>, <class ‘__main__.Medium2‘>, <class ‘__main__.Base‘>, <class ‘object‘>]

可以看到mro方法返回的是一个祖先类的列表。Leaf的每个祖先都在其中出现一次,这也是super在父类中查找成员的顺序。

通过mro,python巧妙地将多继承的图结构,转变为list的顺序结构。super在继承体系中向上的查找过程,变成了在mro中向右的线性查找过程,任何类都只会被处理一次。

通过这个方法,python解决了多继承中的2大难题:

1. 查找顺序问题。从Leaf的mro顺序可以看出,如果Leaf类通过super来访问父类成员,那么Medium1的成员会在Medium2之前被首先访问到。如果Medium1和Medium2都没有找到,最后再到Base中查找。

2. 钻石继承的多次初始化问题。在mro的list中,Base类只出现了一次。事实上任何类都只会在mro list中出现一次。这就确保了super向上调用的过程中,任何祖先类的方法都只会被执行一次。

四、super的使用方法

用法一、super(type, obj)

当我们在Leaf的__init__中写这样的super时:

class Medium1(Base):

    def __init__(self):
        super(Medium1, self).__init__()
        print("Medium1 init")

super(Leaf, self).__init__()的意思是说:

  1. 获取self所属类的mro, 也就是[Leaf, Medium1, Medium2, Base]
  2. 从mro中Leaf右边的一个类开始,依次寻找__init__函数。这里是从Medium1开始寻找
  3. 一旦找到,就把找到的__init__函数绑定到self对象,并返回

从这个执行流程可以看到,如果我们不想调用Medium1的__init__,而想要调用Medium2的__init__,那么super应该写成:super(Medium1, self)__init__()

用法二、super(type, type2)

class Leaf(Medium1, Medium2):

    def __new__(cls):
        obj = super(Leaf, cls).__new__(cls)
        print("Leaf new")
        return obj

super(Leaf, cls).__new__(cls)的意思是说:

  1. 获取cls这个类的mro,这里也是[Leaf, Medium1, Medium2, Base]
  2. 从mro中Leaf右边的一个类开始,依次寻找__new__函数
  3. 一旦找到,就返回“ 非绑定 ”的__new__函数

由于返回的是非绑定的函数对象,因此调用时不能省略函数的第一个参数。这也是这里调用__new__时,需要传入参数cls的原因,同样的,如果我们想从某个mro的某个位置开始查找,只需要修改super的第一个参数就行。

原文地址:https://www.cnblogs.com/Roc-Atlantis/p/9438915.html

时间: 2024-10-09 02:01:43

面向对象super内置函数(转)的相关文章

面向对象进阶------&gt;内置函数 str repr new

__new__方法: 我们来讲个非常非常重要的内置函数和init一样重要__new__其实在实例话对象的开始  是先继承父类中的new方法再执行init的  就好比你生孩子 先要把孩子生出来才能对孩子穿衣服的  new就是生孩子 init是给孩子穿衣服 new()是在新式类中新出现的方法,它作用在构造方法init()建造实例之前,可以这么理解,在Python 中存在于类里面的构造方法init()负责将类的实例化,而在init()调用之前,new()决定是否要使用该init()方法,因为new()

python-38-用于面向对象的内置函数

前言 在面向对象中有很多内置方法,你会发现都很容易知道它的用处与平时用到的函数一样. 1.__str__ 2.__repr__ 3.__len__ 4.__del__ 5.__call__ 6.item系列 7.__new__ 8.__eq__ 9.__hash__ 1.__str__:一旦被调用,就返回调用这个方法的对象的内存地址. # 1.__str__:一旦被调用,就返回调用这个方法的对象的内存地址 class A: def __init__(self,name):self.name=na

面向对象_内置函数与内置方法

老师的博客关于此知识点 http://www.cnblogs.com/Eva-J/articles/7351812.html#_label7 __str__和__repr__ 改变对象的字符串显示__str__,__repr__ 先来看一段代码 class Course: belong_to='old boy' def __init__(self,name,number,site,teacher): self.name=name self.number=number self.site=site

六. python面向对象(内置函数)

一. 内置函数 [email protected] property 内置装饰器函数 只在面向对象中使用 函数的作用是在新式类中返回属性值. from math import pi print(pi) class Circle: def __init__(self,r): self.r=r def per(self): # 周长 return 2*pi*self.r def aer(self): # 面积 return self.r**2*pi aa=Circle(3) print(aa.per

第二十五章 面向对象------封装、内置函数、反射、动态导入

1.封装 什么是封装? 1.对外部隐藏内部的属性,以及实现细节,给外部提供使用的接口 注意:封装有隐藏的意思,但不是单纯的隐藏 学习封装的目的:就是为了能够限制外界对内部数据的访问 python中属性的权限分为两种: 1.公开的 没有任何限制,谁都可以访问 2.私有的 只有当前类本身能狗访问 默认为公共的 为什么要封装? 1.提高安全性 封装属性 2.隔离复杂度 封装方法 一个类中分为两种数据:属性和方法 封装属性 class Student: def __init__(self,name,ag

learn_Day14 内置函数补充、反射、初识面向对象

内置函数 __import__()用于导入模块 getattr 用于寻找模块的指定对象 a = __import__('b')  # b为模块名,b是字符串 ==>> 导入模块b并重新命名为a c = getattr(a,'d')  # d为模块中指定对象 ==>> 找到模块中命名为d的对象 d() ==>> 执行d # getattr(a,'b', c) # 从a模块中导入b.c参数可不写表示找不到报错:c为None表示找不到不报错,返回None. # hasattr

1、面向对象内置函数 2、反射 3、内置方法

1.isinstance()    判断对象所属类型,包括继承关系 2.issubclass() 判断类与类之间的继承关系 class A:pass class B(A): pass print(isinstance(b,B))   # o,t print(isinstance(b,A))  #  o,t class mystr(str): pass ms = mystr("alex") print(type(ms) is str)  # 不包含继承关系,只管一层 print(isin

python 全栈 python基础 (十三)匿名函数 与 内置函数

一.匿名函数  1.定义: 匿名函数顾名思义就是指:是指一类无需定义标识符(函数名)的函数或子程序. 2.语法格式:lambda 参数:表达式 lambda语句中,开头先写关键字lambda,冒号前是参数,可以有多个,用逗号隔开:冒号右边的为表达式,需要注意的是只能有一个表达式.由于lambda返回的是函数对象(构建的是一个函数对象),所以需要定义一个变量去接收.  3.注意点:lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个表达式的值.lambda 函数不能包含命令,包含

python3内置函数详解

一. 简介 python内置了一系列的常用函数,以便于我们使用,python英文官方文档详细说明:点击查看, 为了方便查看,将内置函数的总结记录下来. 二. 使用说明 以下是Python3版本所有的内置函数: 1. abs() 获取绝对值 >>> abs(-10) 10 >>> abs(10) 10 >>> abs(0) 0 >>> a = -10 >>> a.__abs__() 10 2. all() 接受一个迭代