iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Python super(钻石继承)
  • 638
分享到

Python super(钻石继承)

钻石Pythonsuper 2023-01-31 02:01:08 638人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

1.   python的继承以及调用父类成员 Python子类调用父类成员有2种方法,分别是普通方法和super方法 假设Base是基类 class Base(object):   def __init__(self):

1.   python的继承以及调用父类成员

Python子类调用父类成员有2种方法,分别是普通方法和super方法

假设Base是基类


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”

在上面的简单场景下,两种方法的效果一致:

>>> leaf = Leaf()

Base init

Leaf init

当我们来到钻石继承场景时,我们就遇到了一个难题:

如果我们还是使用普通方法调用父类成员,代码如下:

复制代码


class Base(object):
       def __init__(self):
              print “Base init”

class Medium1(Base):
       def __init__(self):
              Base.__init__(self)
              print “Medium1 init”

class Medium2(Base):
       def __init__(self):
              Base.__init__(self)
              print “Medium2 init”

class Leaf(Medium1, Medium2):
       def __init__(self):
              Medium1.__init__(self)
              Medium2.__init__(self)
              print “Leaf init”    

复制代码

当我们生成Leaf对象时,结果如下:

>>> leaf = Leaf()

Base init

Medium1 init

Base init

Medium2 init

Leaf init

 

可以看到Base被初始化了两次!这是由于Medium1和Medium2各自调用了Base的初始化函数导致的。

钻石继承中,父类被多次初始化是个非常难缠的问题,我们来看看其他各个语言是如何解决这个问题的:

3.1. c++

C++使用虚拟继承来解决钻石继承问题。

Medium1和Medium2虚拟继承Base。当生成Leaf对象时,Medium1和Medium2并不会自动调用虚拟基类Base的构造函数,而需要由Leaf的构造函数显式调用Base的构造函数。

3.2. Java

Java禁止使用多继承。

Java使用单继承+接口实现的方式来替代多继承,避免了钻石继承产生的各种问题。

3.3. Ruby

Ruby禁止使用多继承。

Ruby和Java一样只支持单继承,但它对多继承的替代方式和Java不同。Ruby使用Mixin的方式来替代,在当前类中mixin入其他模块,来做到代码的组装效果。

3.4. Python

Python和C++一样,支持多继承的语法。但Python的解决思路和C++完全不一样,Python使用的是super

我们把第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 = Leaf()

Base init

Medium2 init

Medium1 init

Leaf init

可以看到整个初始化过程符合我们的预期,Base只被初始化了1次。而且重要的是,相比原来的普通写法,super方法并没有写额外的代码,也没有引入额外的概念

要理解super的原理,就要先了解mro。mro是method resolution order的缩写,表示了类继承体系中的成员解析顺序。

 

在python中,每个类都有一个mro的类方法。我们来看一下钻石继承中,Leaf类的mro是什么样子的:

>>> Leaf.mro()

[<class '__main__.Leaf'>, <class '__main__.Medium1'>, <class '__main__.Medium2'>, <class '__main__.Base'>, <type '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向上调用的过程中,任何祖先类的方法都只会被执行一次。

 

至于mro的生成算法,可以参考这篇wiki:https://en.wikipedia.org/wiki/C3_linearization

我们首先来看一下python中的super文档

>>> help(super)

Help on class super in module __builtin__:

class super(object)

 |  super(type, obj) -> bound super object; requires isinstance(obj, type)

 |  super(type) -> unbound super object

 |  super(type, type2) -> bound super object; requires issubclass(type2, type)

 

光从字面来看,这可以算是python中最语焉不详的帮助文档之一了。甚至里面还有一些术语误用。那super究竟应该怎么用呢,我们重点来看super中的第1和第3种用法

5.1. super(type, obj)

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


class Leaf(Medium1, Medium2):
       def __init__(self):
              super(Leaf, self).__init__()
              print “Leaf 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__() 

5.2. super(type, type2)

当我们在Leaf中写类方法的super时:


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的第一个参数就行

至此,我们讲解了和super相关的用法及原理,小结一下我们讲过的内容有:

  1. python调用父类成员共有2种方法:普通方法,super方法
  2. 在钻石继承中,普通方法会遇到Base类两次初始化的问题
  3. 简述了其他语言对这个问题的解决方法,并用实例展示了python使用super可以解决此问题
  4. 在讲super具体用法前,先讲了super的内核:mro的知识和原理
  5. 讲解了super两种主要的用法及原理

 原文链接:Http://www.cnblogs.com/testview/p/4651198.html?utm_source=tuicool&utm_medium=referral

--结束END--

本文标题: Python super(钻石继承)

本文链接: https://www.lsjlt.com/news/186851.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python super(钻石继承)
    1.   Python的继承以及调用父类成员 python子类调用父类成员有2种方法,分别是普通方法和super方法 假设Base是基类 class Base(object):   def __init__(self): ...
    99+
    2023-01-31
    钻石 Python super
  • python3--object类,继承与派生,super方法,钻石继承问题
    昨天内容复习组合:什么有什么的关系(例:老师有生日)class Birthday:     def __init__(self, year, month,&nb...
    99+
    2023-01-30
    钻石 方法 object
  • python语法学习之super(),继承与派生
    目录1 什么是继承?2 继承的规则3 继承原理4 多继承属性查询顺序5 查找流程属性查找6 继承概念的实现7 私有属性私有...
    99+
    2022-11-11
  • Python简单几步画个钻石戒指
    目录一、效果演示二、制作步骤/过程(一)绘制戒指(二)绘制雪花三、完整源代码文件一、效果演示 二、制作步骤/过程 (一)绘制戒指 使用tkinter的canvas画布绘制8个点,然...
    99+
    2022-11-11
  • JAVA面向对象中如何继承super
    小编今天带大家了解JAVA面向对象中如何继承super,文中知识点介绍的非常详细。觉得有帮助的朋友可以跟着小编一起浏览文章的内容,希望能够帮助更多想解决这个问题的朋友找到问题的答案,下面跟着小编一起深入学习“JAVA面向对象中如何继承sup...
    99+
    2023-06-28
  • Java由浅入深带你精通继承super
    目录什么是继承背景super关键字protected 关键字final 关键字什么是继承 面向对象的特征: 封装:不必要公开的数据成员和方法,使用private关键字进行修饰。意义:...
    99+
    2022-11-13
  • java继承学习之super的用法解析
    继承supersuper关键字的用法和this关键字的用法相似this:代表本类对象的引用super:代表父类存储空间的标识(可以理解为父类对象引用) package com.it...
    99+
    2022-11-13
  • python 继承与多重继承
    当然,如果不支持python继承,语言特性就不值得称为“类”。派生类定义的语法如下所示: <statement-1> . . . <statement-N> 名称 BaseC...
    99+
    2023-01-31
    python
  • python 继承
    面向对象中的继承关系         1. 经典类             py2: 不继承任何类  2. 新式类             py2: 手动继承object             py3: 所有的类都是object的子类 ...
    99+
    2023-01-30
    python
  • Python-继承
    单继承 多继承 面向对象三大特性 封装根据职责将属性和方法封装到一个抽象的类中 继承实现代码的重用,相同的代码不需要重复的缩写 多态不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度 1.单继承 1.1继承的概念、...
    99+
    2023-10-27
    python linux ubuntu centos pycharm Powered by 金山文档
  • JAVA面向对象之继承 super入门解析
    目录1 继承1.1概念1.2 特点1.3 练习:继承入门案例2 super3 继承的用法3.1 练习:super之继承中成员变量使用3.2 练习:super之继承中构造方法的使用4 ...
    99+
    2022-11-13
  • es6中class继承调用super的原因是什么
    本文小编为大家详细介绍“es6中class继承调用super的原因是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“es6中class继承调用super的原因是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧...
    99+
    2023-07-04
  • Python编程使用matplotlib挑钻石seaborn画图入门教程
    目录scatter_plotlmplotjointplot挑钻石第二弹 seaborn是matplotlib的补充包,提供了一系列高颜值的figure,并且集成了多种在线数据集,通过...
    99+
    2022-11-12
  • python类的继承
    面向对象的三大特性:封装、继承、多态继承时面向对象编程的优点之一类的继承与方法重载:继承的特点:减少代码和灵活定制新类子类具有父类的属性和方法子类不能继承父类的私有属性/方法子类可以添加新的方法子类可以修改父类的方法继承的语法:定义类时,在...
    99+
    2023-01-31
    python
  • python——多重继承
    #方式一 class A():     def __init__(self, name):         self.name = name         print("a class ...") class B():     def ...
    99+
    2023-01-31
    python
  • Python编程matplotlib绘图挑钻石seaborn小提琴和箱线图
    目录箱线图增强箱线图小提琴图想不到大家都这么喜欢用python给女朋友挑钻石,所以我又写了个续。 如果看过之前一篇用python挑钻石的文章,那么可以直接从箱线图开始读。 seabo...
    99+
    2022-11-12
  • Python类中的单继承和多继承用法
    本篇内容主要讲解“Python类中的单继承和多继承用法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Python类中的单继承和多继承用法”吧!前言Python面向对象编程语言,有List、Str...
    99+
    2023-06-02
  • 【Java 基础】引用型数组、Java 继承、super 关键字详解
    《Java 零基础入门到精通》专栏持续更新中。通过本专栏你将学习到 Java 从入门到进阶再到实战的全套完整内容,所有内容均将集中于此专栏。无论是初学者还是有经验的开发人员,都可从本专栏获益。 ...
    99+
    2023-08-31
    java 开发语言 后端
  • 怎么在python中定义单继承和多继承
    本篇文章为大家展示了怎么在python中定义单继承和多继承,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。python的数据类型有哪些python的数据类型:1. 数字类型,包括int(整型)、lon...
    99+
    2023-06-14
  • python中的多继承
    python和C++一样,支持多继承。概念虽然容易,但是困难的工作是如果子类调用一个自身没有定义的属性,它是按照何种顺序去到父类寻找呢,尤其是众多父类中有多个都包含该同名属性。 class P1 #(object):    def foo(...
    99+
    2023-01-31
    python
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作