Python中的Super详解
这篇文章我们来介绍一下 super,我相信大部分的人使用 super 都是使用这种方式;
# 就是我有一个 class 比如说是 Male,然后继承另外一个 class 比如是 Person,然后我在这个 Male 也就是它的子类的 init 函数里面用 super().__init__() 来调用它父类的初识化函数
from objprint import op
class Person:
    def __init__(self, name):
        self.name = name
class Male(Person):
    def __init__(self, name):
        super().__init__(name)
        self.gender = "male"
m = Male('xiaoyang')
op(m)
# 输出:
<Male 0x23669a19fa0
  .gender = 'male',
  .name = 'xiaoyang'
>
 在我们常用 super 的时候都通常会认为 super 是一个方法或者函数,但是实际上 super 是一个正儿八经的 class,它是一个内置内的名字,然后 super() 并不是调用了一个函数 ,super() 是建立 了一个 super 的对象
>>> type(super)
<class 'type'>
 尽管我们更常用的是 super() 括号里面什么都没有,但是 super 的完整版它里面应该是有两个参数,第一个参数是一个 type 也就是一个 class,第二个参数是一个 type 或者是一个 object,其中第二个参数决定了这一个函数绑定到那个 object 或者 class 上,同时第二个参数决定了使用那个 mro,而第一个参数决定了在 mro 链上 从哪个class 开始往后找,例如;
from objprint import op
class Person:
    def __init__(self, name):
        self.name = name
class Male(Person):
    def __init__(self, name):
        # super().__init__(name)
        super(Male, self).__init__(name)
        self.gender = "male"
m = Male('xiaoyang')
op(m)
# 输出:
<Male 0x171f680afa0
  .gender = 'male',
  .name = 'xiaoyang'
>
# 其实我们看刚才的 super().__init__(name) 它是等价于 super(Male, self).__init__(name) 的。
		那么这个super(Male, self)它是做了这样一个事情,首先它要从 self 这个 object 里面拿到 mro,然后他会找到第一个 argument,也就是 Male 在 mro 里所处的位置,那在当前的情况下 Male 就是最开始的那个(Male Person object)接下来他会从 Male 后面的那个 class 开始找,那它第一个找到的就是 Person,然后它就看Person 里面有没有__init__这个函数,然后发现有这个函数,然后它在把这个__init__绑定到 self 上,在这里可以理解为这个 Person 的__init__函数传进去的这个 self 就是 super 里面的这个 self,也就是说Person.__init__(self,name)这行代码等价于 super(Male, self).__init__(name)这行代码。
至于为什么不直接使用Person.__init__(self,name)是有几个原因:
- 在未来有可能会改变基类的名字,甚至会改变继承的方式,在这种情况下如果使用 super 的话就什么都不用管,应为他会自动追随这个 mro 找到正确的 class ,但是用这种命名的 class 的话就要全部修改,这样更容易引起错误
- 其实 super 是动态的,他会根据 self 的 mro 进行寻找,而 self 也就是传进来的这个 argument 它本身是动态的,也就是说同样一个函数里面,我用 super 在不改变这个函数的情况下我有可能会拿到不同的 class。
在来看这个示例:
from objprint import op
class Animal:
    def __init__(self, age):
        self.age = age
class Person(Animal):
    def __init__(self, age, name):
        super().__init__(age)
        self.name = name
class Male(Person):
    def __init__(self,age, name):
        # super(Male, self).__init__(age, name)
        super(Person, self).__init__(age, name)
        self.gender = "male"
m = Male(18, 'xiaoyang')
op(m)
		如果在 Male 中正常的使用它 super(Male, self).__init__(age, name) ,那么它就会正常的初始化所有的东西,它会访问这个 Person 的 __init__ ,然后 Person 的__init__会访问 Animal 的__init__,最后就完成了这个 Male。
		那如果把它改成super(Person, self).__init__(age, name) ,那么就会报错,因为当我们使用 super(Person, self)的时候,self 的 mro 链是 Male Person Animal 然后是  object,那第一个参数它由于是 Person,所以他会从 Person 后面的那个 class 也就是 Animal 开始找,那 Animal 是有__init__函数的,但是 Animal 的 __init__ 只有一个参数 age,所以当我们传入 age name 的时候那就错了,这时候就只需要将它改成只传进去一个 age 如: super(Person, self).__init__(age)  就可以了,同时也跳过了 Person。
总结 super 的两个参数也就是第一个 type 和第二个 type 或者 object 分别决定了什么:
第一个只决定了在 mro 这个链上从哪里开始找
第二个是决定使用这个函数的对象和 mro
super 并不是只能在 class 里面使用的,它可以在任何一个地方使用,我只要给定 第二个参数 object 或者 class ,在给定第一个参数从哪里开始找,我就能使用它的函数,例如:
# 那这里的话就是从 m 这个 object 的 mro 上寻找 Male 后面开始的 __init__ 函数,这样实际上就找到了 Person 的 __init__ 函数,然后再用 Person 的 __init__ 函数对 m 这个 object 做初始化
from objprint import op
class Animal:
    def __init__(self, age):
        self.age = age
class Person(Animal):
    def __init__(self, age, name):
        super().__init__(age)
        self.name = name
class Male(Person):
    def __init__(self,age, name):
        super(Person, self).__init__(age)
        self.gender = "male"
m = Male(18, 'xiaoyang')
op(m)
print("----------------------")
super(Male, m).__init__(20, "xiaoyang")
op(m)
# 输出:
<Male 0x18412d13f70
  .age = 18,
  .gender = 'male'
>
----------------------
<Male 0x18412d13f70
  .age = 20,
  .gender = 'male',
  .name = 'xiaoyang'
>
Python中的Super详解的更多相关文章
- 第7.19节 Python中的抽象类详解:abstractmethod、abc与真实子类
		第7.19节 Python中的抽象类详解:abstractmethod.abc与真实子类 一. 引言 前面相关的章节已经介绍过,Python中定义某种类型是以实现了该类型对应的协议为标准的,而不 ... 
- python中threading模块详解(一)
		python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ... 
- Python中time模块详解
		Python中time模块详解 在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. ... 
- python中常用模块详解二
		log模块的讲解 Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适: logger提供了应用程序可以直接使用的接口API: handler将(logger创建的 ... 
- 76.Python中F表达式详解
		F表达式是用来优化ORM操作数据库的. 举个例子:我们做口罩的公司要将所有员工的薪水增加2000元,如果按照正常的流程,应该是先从数据库中提取所有的员工的工资到Python内存中,然后使用Python ... 
- python 中的unicode详解
		通过例子来看问题是比较容易懂的. 首先来看,下面这个是我新建的一个txt文件,名字叫做ivan_utf8.txt,然后里面随便编辑了一些东西. 然后来用控制台打开这个文件,同样也是截图: 这里就是简单 ... 
- 4、Python中的类详解(0601)
		<大话数据结构>的作者程杰在博客园也有博客,网址是:http://cj723.cnblogs.com/ 面向对象编程(OOP) 1.程序 = 指令 + 数据 代码可以选择以指令为核心或以数 ... 
- python 中model.py详解
		model详解 Django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表. 创建表 基本结构 from django.db import models # Creat ... 
- python 中的map 详解
		python中的map函数应用于每一个可迭代的项,返回的是一个结果list.如果有其他的可迭代参数传进来,map函数则会把每一个参数都以相应的处理函数进行迭代处理.map()函数接收两个参数,一个是函 ... 
随机推荐
- 如何在vscode中编写.net core 项目(vscode)
			1.下载拓展 .NET Core Extension Pack (作者:保哥) 这个里面将需要的插件都打包了小白一键下载就好了 2.下载扩展 vscode-solution-explorer ... 
- 【Java面试宝典】说说你对 Spring 的理解,非单例注入的原理?它的生命周期?循环注入的原理, aop 的实现原理,说说 aop 中的几个术语,它们是怎么相互工作的?
			AOP与IOC的概念(即spring的核心) IOC:Spring是开源框架,使用框架可以使我们减少工作量,提高工作效率并且它是分层结构,即相对应的层处理对应的业务逻辑,减少代码的耦合度.而sprin ... 
- outlook配置osc地址(删除原账户重新配置)
			方法二:使用手动配置邮箱(适用于标准化未入域机器) Step1:在"开始"菜单找到 "控制面板"并打开(或按键盘上的"Win"+" ... 
- 为什么枚举单例在 Java 中更好?
			枚举单例是使用一个实例在 Java 中实现单例模式的新方法.虽然Java中的单例模式存在很长时间,但枚举单例是相对较新的概念,在引入Enum作为关键字和功能之后,从Java5开始在实践中.本文与之前关 ... 
- Java 中怎么获取一份线程 dump 文件?
			在 Linux 下,你可以通过命令 kill -3 PID (Java 进程的进程 ID)来获取 Java 应用的 dump 文件.在 Windows 下,你可以按下 Ctrl + Break 来获取 ... 
- 为什么 wait 和 notify 方法要在同步块中调用?
			Java API 强制要求这样做,如果你不这么做,你的代码会抛出 IllegalMonitorStateException 异常.还有一个原因是为了避免 wait 和 notify 之间产生竞态条件. 
- Math类有哪些常用的方法
			public static int abs(int a) , public static long abs(long a), public static float abs(float a), pu ... 
- thrift源码分析
			1 前言 学习thrift源码主要为了弄清楚几个问题 thrift客户端和服务端的通信流程是如何的 thrift的IDL中给属性加上编号的作用是什么 thrift中require.optional和默 ... 
- 学习笔记 - Sass的安装与使用手册
			最近因为工作需要,自学了Sass.现在将学习笔记整理在这里,供大家参考. 1. Sass的安装 Sass的编辑器安装方法有很多,大致能分为两种:应用程序(application)和命令行界面(comm ... 
- HTML5与类有关的扩充
			对于传统HTML而言,HTML5是一个叛逆.所有之前的版本对JavaScript接口的描述都不过三言两语,主要篇幅都用于定义标记,与JavaScript相关的内容一概交由DOM规范去定义. 而HTML ... 
