浅谈python使用多态跟不用多态的区别_python 多态和 super 用法

python 中的多态实现非常简单,只要是在子类中实现和父类同名的方法,便能实现多态,如果想在子类中调用父类的方法,有多种方法,但是当涉及菱形继承等问题是,super 就成为了比较好的解决方案。

普通继承

对于比较简单的继承关系,通常在子类中有两种方法来执行父类的方法,示例如下。

基类:

1

2

3class Base(object):

def __init__(self):

print("init Base")

示例 1:

1

2

3

4

5

6

7class A(Base):

def __init__(self):

# 通过父类显式执行

Base.__init__(self)

print("init A")

a = A()

输出:

1

2init Base

init A

示例 2:

1

2

3

4

5

6

7class B(Base):

def __init__(self):

# 调用 super

super(B, self).__init__()

print("init B")

b = B()

输出:

1

2init Base

init B

可以看到,两种方法都可以调用父类的方法对父类进行初始化。需要注意的是,两种方法都要传入 self,但是在子类中调用父类的 super 中传入的 self是子类对象。

菱形继承

当有多重继承,特别是菱形继承时,这两种方法就有区别了,示例如下。

示例 1:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20class Base(object):

def __init__(self):

print("init Base")

class A(Base):

def __init__(self):

Base.__init__(self)

print("init A")

class B(Base):

def __init__(self):

Base.__init__(self)

print("init B")

class C(A, B):

def __init__(self):

A.__init__(self)

B.__init__(self)

print("init C")

c = C()

输出:

1

2

3

4

5init Base

init A

init Base

init B

init C

可以看到,Base 被 init 了两次,至于其缺陷,在 C++ 中就已经讨论过了,反正就是不符合我们的预期,不想这种实现。C++ 中通过虚继承解决菱形继承问题,在 python 中可以使用 super 规避这种缺陷。

示例2:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19class Base(object):

def __init__(self):

print("init Base")

class A(Base):

def __init__(self):

super(A, self).__init__()

print("init A")

class B(Base):

def __init__(self):

super(B, self).__init__()

print("init B")

class C(A, B):

def __init__(self):

super(C, self).__init__()

print("init C")

c = C()

输出

1

2

3

4init Base

init B

init A

init C

运行这个新版本后,你会发现每个 __init__() 方法只会被调用一次了。

为了弄清它的原理,我们需要花点时间解释下 python 是如何实现继承的。对于你定义的每一个类,python 会计算出一个所谓的方法解析顺序(MRO)列表。 这个 MRO 列表就是一个简单的所有基类的线性顺序表。我们可以看一下 C 的 MRO 表。

1

2>>>C.__mro__

(__main__.C, __main__.A, __main__.B, __main__.Base, object)

为了实现继承,python 会在 MRO 列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。

而这个 MRO 列表的构造是通过一个 C3 线性化算法来实现的。 我们不去深究这个算法的数学原理,它实际上就是合并所有父类的 MRO 列表并遵循如下三条准则:

子类会先于父类被检查

多个父类会根据它们在列表中的顺序被检查

如果对下一个类存在两个合法的选择,选择第一个父类

必须牢记:MRO 列表中的类顺序会让你定义的任意类层级关系变得有意义。

当使用 super() 函数时,python 会在 MRO 列表上继续搜索下一个类(这是一种嵌套实现)。 只要每个重定义的方法统一使用 super() 并只调用它一次, 那么控制流最终会遍历完整个 MRO 列表,每个方法也只会被调用一次。 这也是为什么在第二个例子中你不会调用两次 Base.__init__() 的原因。换句话说,super 调用了次且仅有一次所有的父类。

由于 super 递归调用的会继续搜索的特性,可能会出现一些意向不到的效果,比如下面这个例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16class A(object):

def spam(self):

print('A.spam')

super(A, self).spam()

class B(object):

def spam(self):

print('B.spam')

class C(A, B):

pass

c = C()

c.spam()

C.__mro__

输出

1

2

3A.spam

B.spam

(__main__.C, __main__.A, __main__.B, object)

为啥 c.spam() 会同时调用 A 和 B 的 spam()?其实看到 MRO 顺序就明白了:

首先在 c 的类 C 中查找 spam 方法,没有找到就查找 A 中的 spam 方法。

调用 A 中的 spam 方法,然后遇到 A 的 super 调用,继续在 MRO 顺序表中查找 spam 方法。注意,这里本来调用了 A 的 spam 就应该返回的,但是 super 的存在,导致了继续递归。

遇到 B 的 spam 方法,调用,结束。

super 的使用

对于 python2 和 python3,super 的用法有一些区别:

原因:

python2 没有默认继承 object

python3 默认全部继承 object 类,都是新式类

用法区别:

python2: super(开始类名,self).函数名()

python3:super().函数名()

参考资料

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/556280.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

战地2服务器怎么虚拟人数,战地2怎么修改作战人数?

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼echo *****************************************************************************************echo AIDefault.ai ****************************************************************************echo ********************…

MySQL锁机制,行锁jingran加在索引上

锁概述 锁是计算机协调多个进程或线程并发访问某一资源的机制,应该都不陌生。?但在这之前我们先来看看并发控制,理清MVCC多版本并发控制和锁的关系,这也是之前我很迷惑的一个点 并发控制技术 在数据库中,数据可以允许多个用户…

pythonweb面试常见问题_python和web框架面试题目整理(3)

1、django为什么需要缓存,有几种缓存方式?答:由于Django是动态网站,部分请求均会去数据库进行相应的操作,当程序的访问量大时,耗时必然会更加明显,最简单解决方式是使用缓存提高读请求的处理效率…

闲置服务器 虚拟服务器,闲置主机搭建服务器

闲置主机搭建服务器 内容精选换一换安装传输工具在本地主机和Windows云服务器上分别安装数据传输工具,将文件上传到云服务器。例如QQ.exe。在本地主机和Windows云服务器上分别安装数据传输工具,将文件上传到云服务器。例如QQ.exe。本地磁盘映射(推荐使用…

浏览器接收响应数据过大_交互响应性能之优化FID

由于 FID 需要一个真实用户的交互,所以无法用实验数据测试。为了在实验数据下预测 FID,通常会用 TBT(Total Blocking Time),具体这个指标后面文章会介绍。他们测量的内容不同,但改善 TBT 通常也能改善 FID。一个糟糕的 FID 主要原…

postman如何发送application/json类的post请求

​ 当接口类型限制为只接受application/json类型的请求,我们使用postman测试的时候怎么选择呢?如下图: 我们需要先在postman上选择POST请求方法,后边输入要请求的地址即可。 在Body选项卡选择raw,然后再后边的下拉选项…

fe文件服务器,FE File Explorer

FE File Explorer是Mac电脑上的一款文件管理应用。FE File Explorer可以访问FTP,SFTP,WebDAV服务器和网络共享上的文件。在这些位置之间传输文件。将电影和歌曲流式传输到Mac。直接在远程位置查看和编辑文档,照片,文件&#xff0c…

swift中文文档_Flutter 中文文档:使用 Packages

Flutter 支持使用其他开发者向 Flutter 和 Dart 生态系统贡献的共享 package,这意味着你可以快速构建应用而不是一切从零开始。现有的 package 支持许多使用场景,例如,网络请求 (http),自定义导航/路由处理 (fluro),集…

Spring深入理解之ComponentScan___@ComponentScan 详解

Spring深入理解之ComponentScan 一、概述 ComponentScan顾名思义包扫描,底层其实就可以通过递归算法反射将其装载成bean来实现的,实在开发过程中,Spring已经帮我们实现好了,我们其实就可以直接使用XML或者注解的形式来进行业务处…

云服务器centos怎么还原系统还原,云服务器centos怎么还原系统还原

云服务器centos怎么还原系统还原 内容精选换一换云耀云服务器(Halo Elastic Cloud Server,HECS)是可以快速搭建简单应用的新一代云服务器,具备独立、完整的操作系统和网络功能。提供快速地应用部署和简易的管理能力,适用于网站搭建、开发环境…

高倍数泡沫装置PHP_泡沫灭火系统,了解这几点就好

1 集输站库泡沫灭火系统的构成油区的泡沫灭火系统主要由消防水泵、消防水源、泡沫灭火剂储存装置、泡沫比例混合装置、泡沫产生装置及管道等组成。泡沫液按发泡倍数不同可分为低倍数泡沫液、中倍数泡沫液和高倍数泡沫液。发泡倍数 20 以下的称为低倍数泡沫液, 发泡倍…

Spring注解——使用@ComponentScan自动扫描组件

1.创建一个配置类&#xff0c;在配置类上添加 ComponentScan 注解。该注解默认会扫描该类所在的包下所有的配置类&#xff0c;相当于之前的 <context:component-scan>。 package io.mieux.config;import org.springframework.context.annotation.ComponentScan;Componen…

python io多路复用_Python之IO多路复用

一、IO模型介绍​ 同步(synchronous) IO和异步(asynchronous) IO&#xff0c;阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么&#xff0c;到底有什么区别&#xff1f;这个问题其实不同的人给出的答案都可能不同&#xff0c;比如wiki&#xff0c;就认为asynchronous IO和…

MySQL中TEXT数据类型的最大长度___MySQL VARCHAR字段最大长度究竟是多少

MySQL TEXT数据类型的最大长度 TINYTEXT256 bytesTEXT65,535 bytes~64kbMEDIUMTEXT16,777,215 bytes~16MBLONGTEXT4,294,967,295 bytes~4GB MySQL中VARCHAR字段最大长度究竟是多少 varchar(n)&#xff0c;n表示什么&#xff1f; MySQL5.0.3之前varchar(n)这里的n表示字节数 …

python自动化_Python 实现Excel自动化办公上

今天的文章分享Python 如何轻松操作Excel 这款office 办公软件的&#xff0c;在Python 中你要针对某个对象进行操作&#xff0c;是需要安装与其对应的第三方库的&#xff0c;这里对于Excel 也不例外&#xff0c;它也有对应的第三方库&#xff0c;即xlrd 库。什么是xlrd库Python…

utf8编码为什么这么普遍,优势在哪里?

为什么需要字符集 计算机存储的和认识的东西就是0和1&#xff0c;我们存储的任何东西最后都会转为0和1的组合计算机才能处理&#xff0c;更贴切的说是我们看到的英文、中文等都是0和1组合的二进制经过一定规则转换为我们认识的字符&#xff0c;这个规则就是字符集。 有哪些字…

SpringBoot默认包扫描机制及@ComponentScan指定扫描路径详解

SpringBoot默认包扫描机制及ComponentScan指定扫描路径详解 SpringBoot默认包扫描机制 标注了Component和Component的衍生注解如Controller,Service,Repository就可以把当前的Bean加入到IOC容器中。那么SpringBoot是如何知道要去扫描Component注解的呢。ComponentScan做的事情…

raid卡组不同raid_RAID 类型介绍

RAID (Redundant Array of Independent/InexpensiveDisks)&#xff0c;独立磁盘冗余阵列&#xff0c;是一种将多块独立的硬盘(物理硬盘)按不同的组合方式形成一个硬盘组(逻辑硬盘)&#xff0c;从而提供比单块硬盘更大的存储容量、更高的可靠性和 更快的读写性能等。该概念最早由…

springboot前端传参date类型后台处理方式

springboot前端传参date类型后台处理方式 先说结论&#xff1a;建议大家直接使用JsonFormat&#xff0c;原因如下&#xff1a; 1、针对json格式&#xff1a;在配置文件中加以下配置 spring.jackson.date-formatyyyy-MM-dd HH:mm:ssspring.jackson.time-zoneGMT82、针对form表…

python2.7 end=号报错_python2 post 上传压缩文件编码报错

python版本是2.7&#xff0c;使用urllib2将文件推送至微信&#xff0c;在上传文件时&#xff0c;碰到这样一个问题&#xff1a;上传未经压缩的文本文件&#xff0c;可以成功&#xff1b;上传经过压缩的二进制文件&#xff0c;则提示编码错误代码如下def upload_tmpfile_old(sel…