Python 基础合集8:类的继承和多态

2023-11-01

一、前言

本小节主要梳理类的继承和多态,继承包含三种形式:单继承、多层继承、多重继承。

环境说明:Python 3.6、windows11 64位

二、继承

基础语法如下,class B(A)表示的含义就是B 继承A ,A 是B 的父类。

class A():
    name='Xindata'
class B(A):
    pass

2.1 单继承

子类继承父类之后,父类的所有属性和方法,子类都可以直接调用。

class A():
    name='Xindata'
    @classmethod
    def func1(cls):
        print('My name is %s.'%cls.name)
class B(A):
    pass

# 子类调用父类属性和方法
print(B.name)
B.func1()
# 结果为:
# Xindata
# My name is Xindata.

子类继承父类之后,父类的所有实例属性和方法,子类实例化之后都可以调用。但是子类直接调用父类实例属性和方法则会报错,其实这点和父类本身调用父类实例属性和方法类似,实例的属性和方法不属于类本身,要实例化之后才能进行调用
如果相关的基础不够扎实可以看看上一篇《类和实例》2.2.2 实例化调用部分内容。

class A():
    name='Xindata'
    @classmethod
    def func1(cls):
        print('My name is %s.'%cls.name)
    def func2(self):
        print('I\'m instance.')
class B(A):
    pass

# 子类调用父类属性和方法
print(B.name)  # 结果为:Xindata
B.func1()      # 结果为:My name is Xindata.
# B.func2()

# 子类实例化后调用父类和父类的实例的属性和方法
b = B()
print(b.name)  # 结果为:Xindata
b.func1()      # 结果为:My name is Xindata.
b.func2()      # 结果为:I'm instance.

继承带__init__()函数的父类,为了获得父类的初始化属性和方法,可以通过调用父类的初始函数实现,如下代码第8行,直接调用类A的初始函数,这样子对类B进行实例化的时候,就可以调用父类的初始化属性和方法,同时也可以在子类的初始函数新增属性。

class A():
    def __init__(self,name):
        self.name = name
    def func1(self):
        print('My name is %s.'%self.name)
class B(A):
    def __init__(self,name):
        A.__init__(self,name)   # 调用类A 的初始函数
        self.eye = 'black'
        
b=B('Xindata')
b.func1()      # 结果为:My name is Xindata.

调用父类的初始化属性和方法,除了通过调用父类的初始化函数,还可以通过super()函数实现。使用super()函数时注意不需要给参数self传递值。

super() 函数是用于调用父类(超类)的一个方法。主要是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承(后两小节介绍),会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。

class A():
    def __init__(self,name):
        self.name = name
    def func1(self):
        print('My name is %s.'%self.name)
class B(A):
    def __init__(self,name):
        super().__init__(name)   # 注意,不需要参数self 
        self.eye = 'black'
        
b=B('Xindata')
b.func1()      # 结果为:My name is Xindata.

接下来看看一些从属关系,借助函数isinstance()issubclass()辅助理解。

  • isinstance()判断参数1的实例是否是参数2的类的实例。语法:isinstance([实例名], [类名])
  • issubclass()判断参数1的类是不是参数2的类的子类。语法:issubclass([类名1], [类名2])

子类的实例属于父类,父类的实例不属于子类。

class A():
    name='Xindata'
    @classmethod
    def func1(cls):
        print('My name is %s.'%cls.name)
    def func2(self):
        print('I\'m instance.')
class B(A):
    pass

a = A()
b = B()

# 实例和类
print(isinstance(a,A)) # True,父类实例属于父类
print(isinstance(a,B)) # False,父类实例不属于子类
print(isinstance(b,B)) # True,子类实例属于类子
print(isinstance(b,A)) # True,子类实例属于父类
# 子类和父类,如果是实例会报错
print(issubclass(B,A)) # True,B是A的子类
print(issubclass(A,B)) # False
# print(issubclass(a,B)) # 报错
# print(issubclass(b,A)) # 报错

2.2 多层继承

多层继承,或者叫多级继承,就是父类继承祖父类,子类继承父类,孙类继承子类,一级一级传参。最后的一个类继承了前面所有类的属性和方法。

class A():
    name='Xindata'
    @classmethod
    def func1(cls):
        print('My name is %s.'%cls.name)
    def func2(self):
        print('I\'m instance.')
class B(A):
    @classmethod
    def func3(cls):
        print('class B')
class C(B):
    @classmethod
    def func4(cls):
        print('class C')

print(C.name)   # 结果为:Xindata
C.func1()       # 结果为:My name is Xindata.
C.func3()       # 结果为:class B
C.func4()       # 结果为:class C

多层继承遵循就近原则,如果父类和祖父类都有func1()方法,则子类从父类获取相关的属性和方法;如果父类没有func1()方法,再到祖父类中获取,如果祖父类也没有相关方法则报错。如果是子类也含有func1()方法,则直接取子类的。
注意:如果父类和祖父类同时都有某个属性或方法,祖父类的相关属性方法会被父类覆盖,此时如果某属性在父类没有,但在祖父类中有,子类也不能调用该属性,具体看看下例的name属性,该属性仅在祖父类A存在,但是在父类B所在的方法被重写,在调用类C时,可以看做A.func1()不存在过,所以C.name不会到Afunc1()方法中寻找属性name,而是返回错误:ttributeError: type object ‘C’ has no attribute ‘name’。

class A():
    @classmethod
    def func1(cls):
        cls.name = 'class A.func1.name'
        cls.hair = 'class A.func1.hair'
        print('class A.func1')
    
    @classmethod
    def func2(cls):
        print('class A.func2')  

class B(A):
    @classmethod
    def func1(cls):       # 重写父类A 的func1()函数,新增功能
        cls.skill_1 = 'class B.func1.skill_1'
        cls.hair = 'class B.func1.hair'
        print('class B.func1')

class C(B):
    @classmethod
    def func3(cls):
        print('class C.func3')


C.func1() # 结果为:class B.func1
C.func2() # 结果为:class A.func2
C.func3() # 结果为:class C.func3

print(C.hair)    # 结果为:class B.func1.hair
print(C.skill_1) # 结果为:class B.func1.skill_1
# print(C.name)    # 报错

2.3 多重继承

类的多重继承,即同时继承多个类。基本语法:

class A():
    pass
class B():
    pass
class C(B,A):
    pass

多重继承也有一个“就近原则”,就是靠近左侧的类优先调用。在调用子类的某个属性或方法的时候,如果子类本身没有,则从继承的父类中,依次从左到右找寻相关的属性和方法。
当继承的类中有相同的属性或方法的时候,多重继承和多层继承一样有一个先后调用的顺序,只调用了排在靠左侧的类的相关属性和方法,忽略靠右侧的类的相关属性和方法。如下代码,父类B和父类A都有func1()方法,由于类B在左侧,所以子类C优先继承父类B的方法func1,而忽略类A的方法func1。而类属性name在类A的方法func1中,所以类C没有继承到类A的属性name,当执行C.name时报错:AttributeError: type object ‘C’ has no attribute ‘name’。

class A():
    @classmethod
    def func1(cls):
        cls.name = 'class A.func1.name'
        cls.hair = 'class A.func1.hair'
        print('class A.func1')
    
    @classmethod
    def func2(cls):
        print('class A.func2')  

class B():
    @classmethod
    def func1(cls):   
        cls.skill_1 = 'class B.func1.skill_1'
        cls.hair = 'class B.func1.hair'
        print('class B.func1')

class C(B,A):
    @classmethod
    def func3(cls):
        print('class C.func3')


C.func1() # 结果为:class B.func1
C.func2() # 结果为:class A.func2
C.func3() # 结果为:class C.func3

print(C.hair)    # 结果为:class B.func1.hair
print(C.skill_1) # 结果为:class B.func1.skill_1
print(C.name)    # 报错

三、多态

多态,我的理解就是在不同的类中使用同样的方法名称,实现某一类功能,调用相关方法时,解释器把调用分派给正确的方法。
不管对象属于哪个类,也不管声明的具体接口是什么,只要对象实现了相应的方法,函数就可以在对象上执行操作。
具体看以下代码,对AnimalCatDog三个类分别实例化然后分别调用各个类的run()方法,虽然名称相同,但是解释器可以把相关的调用给正确的方法,打印出正确的值。

class Animal():
    def run(self):
        print('Anaimal running')
class Cat(Animal):
    def run(self):
        print('Cat running')
class Dog(Animal):
    def run(self):
        print('Dog running')

A = Animal()
C = Cat()
D = Dog()
for animal in [A,C,D]:
    animal.run()
# 结果为:
# Anaimal running
# Cat running
# Dog running

四、小结

本节主要的知识点框架如下:
类的继承和多态.png




<下节预告:模块和包>


- End -

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 基础合集8:类的继承和多态 的相关文章

随机推荐

  • 类默认成员函数 - 析构函数

    析构函数与构造函数就是功能截然相反的两个函数了 析构函数就是将对象内部的资源进行清理 如malloc开辟的等 值得注意的是 很多人误以为析构函数是销毁对象 对象的销毁工作是由编译器完成的 我们现在说说析构函数的有那些特性 1 还是重析构函数
  • 咖说丨一文了解区块链在医疗领域的应用案例

    收集一众行业大咖观点 探索区块链商业及应用 百家争鸣 百花齐放 说理 解密 预测和八卦 了解行业内幕 看咖说就够了 投稿请联系 tougao conflux chain org 本文转自 白话区块链 作者 Wayne 换了一家医院就诊就要重
  • 阿里手淘猜你喜欢Swing算法介绍

    Swing算法原理比较简单 是阿里早期使用到的一种召回算法 在阿里多个业务被验证过非常有效的一种召回方式 它认为 user item user 的结构比 itemCF 的单边结构更稳定 Swing指的是秋千 例如用户 u uu 和用户 v
  • Shell常用的几个正则表达式:[:alnum:], [:alpha:], [:upper:], [:lower:], [:digit:] 认知

    一 通配符命令简介 匹配符合相关条件的符号 匹配文件名查找 通配符类型 匹配任意长度的任意字符 匹配任意单个字符 匹配指定范围内的任意单个字符 匹配指定范围之外的任意单个字符 space 空白字符 punct 标点符号 lower 小写字母
  • 由java转c++ 和qt的学习心得

    接触qt有一周左右了 写下这篇文章 用于反思自己前几日浑浑噩噩 也用于警醒自己 我是从java转到c 到qt开发的 原先以为编程语言是相通的 但是接触之后才发现 换一种新语言学 很难 接下来回顾两点 一 c 的学习思考 c 中 我认为最为重
  • 21.shell语言之if条件判断语句

    个人简介 作者简介 大家好 我是小鹏linux 运维领域新星创作者 个人主页 小鹏linux 支持我 点赞 收藏 留言 格言 你未必出类拔萃 但一定与众不同 系列专栏 阶段一 windows基础 原创16篇 阶段二 Linux基础知识 原创
  • Mac安装Redis后的配置

    Mac安装Redis后的配置 找到安装目录 配置文件修改 启动服务做测试连接 找到安装目录 1 双击 右键 访达 点击前往文件夹进行查找 如下图所示 2 然后再如下图所示中找到如下路径 usr local bin 3 找到redis con
  • hibernate mysql 超时_Hibernate连接数据库超时设置autoReconnect=true

    com mysql jdbc CommunicationsException The last packet successfully received from the server was58129 seconds ago The la
  • 小程序云开发——图片视频资源上传云端并返回云端路径

    在现在的应用中 包括小程序 图片视频等元素是产品必不可少的一部分 如果一个产品仅支持文字 将会很单调 有时候我们需要将图片视频上传到云端或者服务器 我这里将介绍在小程序中怎么上传图片和视频到云端 并返回云端路径 可以将这个云端路径存入数据库
  • 第三讲:IP地址和子网掩码

    一 标准分类的IP地址 每台计算机都要有IP地址 有了IP地址才能互相通信 计算机之间只能互相认识IP地址 IP地址可以理解为计算机的身份证号 一 二进制和十进制数转换 记住 10000000 2 128 10 1000000 2 64 1
  • PhpStorm+Xdebug+PHPStudy配置并调试

    首先 火狐浏览器搜索插件并安装 配置IDE key 打开phpinfo 将内容复制到Xdebug Support Tailored Installation Instructions 会推荐你适合版本的xdebug 当然你也可以选择phps
  • UE4 全局变量的应用(蓝图)

    4 20 1 创建全局变量 命名为MyGameInstance 2 创建一个变量 命名为MyB 3 在项目设置中 搜索GameInstence 并选中创建的全局变量 4 在蓝图里调用全局变量 5 成功打印
  • Tmux使用教程

    Tmux 是一款可以管理会话和分屏的终端复用器 在远程 SSH 断开后可以继续执行任务 重新连接后再继续会话 也能够将进程放到后台运行 需要时重新接管 为了防止 SSH 因网络断开造成的进程运行中断 推荐把所有需要长期运行的训练等任务都使用
  • 提升效率之如何打印出漂亮的带颜色的日志(输出高亮)

    花里胡哨的日志 1 花里胡哨的shell打印 2 c语言日志的彩色输出 日志系统对于一个软件的维护是很重要的 对于直接在本地打印的信息 可能包含非常多 如何才能快速发现自己想要打印的东西呢 带上颜色的输出 绝对是很好的选择 使用c c 的输
  • 二、网络编程之协议及协议格式详解

    引言 在网络编程中 我经常听人提起过协议 标准协议 协议族 TCP协议 传输层协议 诸如此类的协议概念 这些种类繁多的名词听着让人感觉头晕 所以今天继续学习和总结协议的相关知识 在前面一篇文章 网络编程之基础知识详解 中已经简单介绍过协议
  • vue3中使用echart多个图表,并且可以随着屏幕大小自适应布局

    一 在项目中安装echarts npm install echarts save 二 引入echarts 1 因为多个地方需要使用到这个echart图表 所以将这个echarts写在自定义组件中 子组件 chart vue div clas
  • Linux进程控制编程实验_02

    任务1 编写一个进程创建实验程序task51 c 创建如图所示的进程族亲结构 其中p1是程序启动时由加载程序创建第一个进程 各进程的输出信息分别如下 p1 I am father process p11 当前时间是 lt 年 月 日 时 分
  • Eclipse CDT c++支持C++11

    最近要在Linux 环境下面写一些代码 需要支持C 11 可是CDT 不认识C 11的特性 看了很多网上的配置资料 各种版本下面还是不一样 Eclipse 16 04 CDT 9 4 GCC 5 4 首先创建一个C project 写点C
  • mysql知识系列:用命令行远程登录Mysql

    参考 命令行登录Mysql 远程登录Mysql的方法 总结 mysql uxxx pxxx hxxx xxx xxx xxx P3306 xxx 为替换的内容
  • Python 基础合集8:类的继承和多态

    一 前言 本小节主要梳理类的继承和多态 继承包含三种形式 单继承 多层继承 多重继承 环境说明 Python 3 6 windows11 64位 二 继承 基础语法如下 class B A 表示的含义就是B 继承A A 是B 的父类 cla