一、单独调用父类的方法

需求:编写一个类,然后再写一个子类进行继承,使用子类去调用父类的方法1。

使用方法1打印: 胖子老板,来包槟榔。

那么先写一个胖子老板的父类,执行一下:

class FatFather(object):
def __init__(self, name):
print('FatFather的init开始被调用')
self.name = name
print('FatFather的name是%s' % self.name)
print('FatFather的init调用结束') def main():
ff = FatFather("胖子老板的父亲")

运行一下这个胖子老板父类的构造方法__init__ 如下:

if __name__ == "__main__":
main()
FatFather的init开始被调用
FatFather的name是胖子老板的父亲
FatFather的init调用结束

好了,那么下面来写一个子类,也就是胖子老板类,继承上面的类

# 胖子老板的父类
class FatFather(object):
def __init__(self, name):
print('FatFather的init开始被调用')
self.name = name
print('调用FatFather类的name是%s' % self.name)
print('FatFather的init调用结束') # 胖子老板类 继承 FatFather 类
class FatBoss(FatFather):
def __init__(self, name, hobby):
print('胖子老板的类被调用啦!')
self.hobby = hobby
FatFather.__init__(self, name) # 直接调用父类的构造方法
print("%s 的爱好是 %s" % (name, self.hobby)) def main():
#ff = FatFather("胖子老板的父亲")
fatboss = FatBoss("胖子老板", "打斗地主")

在这上面的代码中,我使用FatFather.__init__(self,name)直接调用父类的方法。

运行结果如下:

if __name__ == "__main__":
main()
胖子老板的类被调用啦!
FatFather的init开始被调用
调用FatFather类的name是胖子老板
FatFather的init调用结束
胖子老板 的爱好是 打斗地主

二、super() 方法基本概念

除了直接使用 FatFather.__init__(self,name) 的方法,还可以使用super()方法来调用。

那么首先需要看super()方法的描述和语法理解一下super() 方法的使用。

2.1 描述

super() 函数是用于调用父类(超类)的一个方法。

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

MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。

2.2 语法

以下是 super() 方法的语法:

super(type[, object-or-type])

参数

  • type -- 类

  • object-or-type -- 类,一般是 self

Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx :

  • Python3.x 实例:
class A:
pass
class B(A):
def add(self, x):
super().add(x)
  • Python2.x 实例:
class A(object):   # Python2.x 记得继承 object
pass
class B(A):
def add(self, x):
super(B, self).add(x)

2.3 单继承使用super()

  • 使用super() 方法来改写刚才胖子老板继承父类的 __init__ 构造方法
# 胖子老板的父类
class FatFather(object):
def __init__(self, name):
print('FatFather的init开始被调用')
self.name = name
print('调用FatFather类的name是%s' % self.name)
print('FatFather的init调用结束') # 胖子老板类 继承 FatFather 类
class FatBoss(FatFather):
def __init__(self, name, hobby):
print('胖子老板的类被调用啦!')
self.hobby = hobby
#FatFather.__init__(self,name) # 直接调用父类的构造方法
super().__init__(name)
print("%s 的爱好是 %s" % (name, self.hobby)) def main():
#ff = FatFather("胖子老板的父亲")
fatboss = FatBoss("胖子老板", "打斗地主")

从上面使用super方法的时候,因为是单继承,直接就可以使用了。

运行如下:

if __name__ == "__main__":
main()
胖子老板的类被调用啦!
FatFather的init开始被调用
调用FatFather类的name是胖子老板
FatFather的init调用结束
胖子老板 的爱好是 打斗地主

那么为什么说单继承直接使用就可以呢?因为super()方法如果多继承的话,会涉及到一个MRO(继承父类方法时的顺序表) 的调用排序问题。

下面可以打印一下看看单继承的MRO顺序(FatBoss.mro)。

# 胖子老板的父类
class FatFather(object):
def __init__(self, name):
print('FatFather的init开始被调用')
self.name = name
print('调用FatFather类的name是%s' % self.name)
print('FatFather的init调用结束') # 胖子老板类 继承 FatFather 类
class FatBoss(FatFather):
def __init__(self, name, hobby):
print('胖子老板的类被调用啦!')
self.hobby = hobby
#FatFather.__init__(self,name) # 直接调用父类的构造方法
super().__init__(name)
print("%s 的爱好是 %s" % (name, self.hobby)) def main(): print("打印FatBoss类的MRO")
print(FatBoss.__mro__) print()
print("=========== 下面按照 MRO 顺序执行super方法 =============")
fatboss = FatBoss("胖子老板", "打斗地主")

上面的代码使用 FatBoss.__mro__ 可以打印出 FatBoss这个类经过 python解析器的 C3算法计算过后的继承调用顺序。

运行如下:

if __name__ == "__main__":
main()
打印FatBoss类的MRO
(<class '__main__.FatBoss'>, <class '__main__.FatFather'>, <class 'object'>) =========== 下面按照 MRO 顺序执行super方法 =============
胖子老板的类被调用啦!
FatFather的init开始被调用
调用FatFather类的name是胖子老板
FatFather的init调用结束
胖子老板 的爱好是 打斗地主

从上面的结果 (<class '__main__.FatBoss'>, <class '__main__.FatFather'>, <class 'object'>) 可以看出,super() 方法在 FatBoss 会直接调用父类是 FatFather ,所以单继承是没问题的。

那么如果多继承的话,会有什么问题呢?

2.4 多继承使用super()

假设再写一个胖子老板的女儿类,和 胖子老板的老婆类,此时女儿需要同时继承 两个类(胖子老板类,胖子老板老婆类)。

因为胖子老板有一个爱好,胖子老板的老婆需要干活干家务,那么女儿需要帮忙同时兼顾。

此时女儿就是需要继承使用这两个父类的方法了,那么该如何去写呢?

下面来看看实现代码:

# 胖子老板的父类
class FatFather(object):
def __init__(self, name, *args, **kwargs):
print()
print("=============== 开始调用 FatFather ========================")
print('FatFather的init开始被调用')
self.name = name
print('调用FatFather类的name是%s' % self.name)
print('FatFather的init调用结束')
print()
print("=============== 结束调用 FatFather ========================") # 胖子老板类 继承 FatFather 类
class FatBoss(FatFather):
def __init__(self, name, hobby, *args, **kwargs):
print()
print("=============== 开始调用 FatBoss ========================")
print('胖子老板的类被调用啦!')
#super().__init__(name)
## 因为多继承传递的参数不一致,所以使用不定参数
super().__init__(name, *args, **kwargs)
print("%s 的爱好是 %s" % (name, hobby))
print()
print("=============== 结束调用 FatBoss ========================") # 胖子老板的老婆类 继承 FatFather类
class FatBossWife(FatFather):
def __init__(self, name, housework, *args, **kwargs):
print()
print("=============== 开始调用 FatBossWife ========================")
print('胖子老板的老婆类被调用啦!要学会干家务')
#super().__init__(name)
## 因为多继承传递的参数不一致,所以使用不定参数
super().__init__(name, *args, **kwargs)
print("%s 需要干的家务是 %s" % (name, housework))
print()
print("=============== 结束调用 FatBossWife ========================") # 胖子老板的女儿类 继承 FatBoss FatBossWife类
class FatBossGril(FatBoss, FatBossWife):
def __init__(self, name, hobby, housework):
print('胖子老板的女儿类被调用啦!要学会干家务,还要会帮胖子老板斗地主')
super().__init__(name, hobby, housework) def main(): print("打印FatBossGril类的MRO")
print(FatBossGril.__mro__) print()
print("=========== 下面按照 MRO 顺序执行super方法 =============")
gril = FatBossGril("胖子老板", "打斗地主", "拖地")

运行结果如下:

if __name__ == "__main__":
main()
打印FatBossGril类的MRO
(<class '__main__.FatBossGril'>, <class '__main__.FatBoss'>, <class '__main__.FatBossWife'>, <class '__main__.FatFather'>, <class 'object'>) =========== 下面按照 MRO 顺序执行super方法 =============
胖子老板的女儿类被调用啦!要学会干家务,还要会帮胖子老板斗地主 =============== 开始调用 FatBoss ========================
胖子老板的类被调用啦! =============== 开始调用 FatBossWife ========================
胖子老板的老婆类被调用啦!要学会干家务 =============== 开始调用 FatFather ========================
FatFather的init开始被调用
调用FatFather类的name是胖子老板
FatFather的init调用结束 =============== 结束调用 FatFather ========================
胖子老板 需要干的家务是 拖地 =============== 结束调用 FatBossWife ========================
胖子老板 的爱好是 打斗地主 =============== 结束调用 FatBoss ========================

从上面的运行结果来看,我特意给每个类的调用开始以及结束都进行打印标识,可以看到。

每个类开始调用是根据MRO顺序进行开始,然后逐个进行结束的。

还有就是由于因为需要继承不同的父类,参数不一定。

所以,所有的父类都应该加上不定参数*args , **kwargs ,不然参数不对应是会报错的。

三、注意事项

  • super().__init__相对于类名.__init__,在单继承上用法基本无差

  • 但在多继承上有区别,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次,可以尝试写个代码来看输出结果

  • 多继承时,使用super方法,对父类的传参数,应该是由于python中super的算法导致的原因,必须把参数全部传递,否则会报错

  • 单继承时,使用super方法,则不能全部传递,只能传父类方法所需的参数,否则会报错

  • 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍, 而使用super方法,只需写一句话便执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因

四、练习

以下的代码的输出将是什么? 说出你的答案并解释。

class Parent(object):
x = 1 class Child1(Parent):
pass class Child2(Parent):
pass print(Parent.x, Child1.x, Child2.x)
1 1 1
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
1 2 1
  • 注意:Child1已经拥有了属于自己的x
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
3 2 3

super()方法详解的更多相关文章

  1. Android ActionBar 关于tab的应用 以及 TabListener的方法详解

    actionBar的tab标签应用以及TabListener的方法详解 package com.example.actionBarTest.actionBarTab; import android.a ...

  2. Clone使用方法详解【转载】

    博客引用地址:Clone使用方法详解 Clone使用方法详解   java“指针”       Java语言的一个优点就是取消了指针的概念,但也导致了许多程序员在编程中常常忽略了对象与引用的区别,本文 ...

  3. Python 在子类中调用父类方法详解(单继承、多层继承、多重继承)

    Python 在子类中调用父类方法详解(单继承.多层继承.多重继承)   by:授客 QQ:1033553122   测试环境: win7 64位 Python版本:Python 3.3.5 代码实践 ...

  4. Android——onCreate( )方法详解(转)

    android开发之onCreate( )方法详解 onCreate( )方法是android应用程序中最常见的方法之一,那么,我们在使用onCreate()方法的时候应该注意哪些问题呢? 先看看Go ...

  5. Android编程之LayoutInflater的inflate方法详解

    LayoutInflater的inflate方法,在fragment的onCreateView方法中经常用到: public View onCreateView(LayoutInflater infl ...

  6. 【Python】Linux crontab定时任务配置方法(详解)

    CRONTAB概念/介绍 crontab命令用于设置周期性被执行的指令.该命令从标准输入设备读取指令,并将其存放于“crontab”文件中,以供之后读取和执行. cron 系统调度进程. 可以使用它在 ...

  7. ES6 类(Class)基本用法和静态属性+方法详解

    原文地址:http://blog.csdn.net/pcaxb/article/details/53759637 ES6 类(Class)基本用法和静态属性+方法详解 JavaScript语言的传统方 ...

  8. java多线程并发(二)--线程的生命周期及方法详解

    上篇随笔介绍了线程的相关基础知识以及新启线程的几种方法,本片将继续介绍线程的生命周期及方法详解. 一.线程的生命周期 在Thread代码中,线程的状态被分为6种 public enum State { ...

  9. 并发编程(六)Object类中线程相关的方法详解

    一.notify() 作用:唤醒一个正在等待该线程的锁的线程 PS : 唤醒的线程不会立即执行,它会与其他线程一起,争夺资源 /** * Object类的notify()和notifyAll()方法详 ...

随机推荐

  1. css知识笔记:水平垂直居中(别只看,请实操!!!)

    css实现元素的水平垂直居中. (尝试采用5W2H方法说明): 别只看,请实操!!! What: 1.这篇文档主要描述元素水平方向居中的几种最常见和最实用的几种方式,并说明优缺点. 2.写这篇文章的目 ...

  2. 从零开始学vuejs

    最近一段时间都花在了学习vue上,还总是断断续续的,学习的效果不是很明显,思考了好久了,应该是没有进行一个系统的总结,导致很多知识点总是似是而非,而且也有一部分是思维还没有从java转变过来,废话不多 ...

  3. ImageView设置rounded corner

    版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/207 ImageView设置rounded corner ...

  4. solo升级以及自动化更新的方法

    使用solo过程总涉及到更新问题,所以就在这里把solo更新的方法总结一下.希望能给小伙伴们一些帮助.如何选择更新方法主要是跟你的部署方式有关,如果你是通过 docker方式进行部署,那么你可以还可以 ...

  5. V4 Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup (Doc ID 2471245.1)

    V4 Reduce Transportable Tablespace Downtime using Cross Platform Incremental Backup (Doc ID 2471245. ...

  6. center----Iframe 用法的详细讲解

    把iframe解释成“浏览器中的浏览器“很是恰当 <iframe frameborder=0 width=170 height=100 marginheight=0 marginwidth=0 ...

  7. quarter软件的破解

    链接;http://www.openedv.com/forum.php?mod=viewthread&tid=275857&extra=page%3D1 这个是正点原子提供的破解方法, ...

  8. Java中文本文件的读取(按行读取)

    在之前的学习过程中,经常会遇到将文本文件中的数据读取到数组或其他数据结构中.每次遇到,总是在网上搜索代码解决,解决之后并没有总结复习,因此在下一次遇到同样的问题时,又重复之前的过程.这样周而复始,并没 ...

  9. [译]Vulkan教程(12)图形管道基础之入门

    [译]Vulkan教程(12)图形管道基础之入门 Introduction 入门 Over the course of the next few chapters we'll be setting u ...

  10. 分布式文件服务器FastDFS的使用

    分布式项目中涉及到的文件上传与下载,此时使用之前的上传方式,将上传的文件与当前项目所在服务器放在同一个位置,显然不符合分布式项目的理念,此时我们借助FastDFS将上传的文件数据存储到单纯的一个服务器 ...