百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Python中的多态及抽象类(python的多态和java多态)

off999 2024-10-25 13:43 47 浏览 0 评论

本书同名免费MOOC《Python编程基础及应用》在哔哩哔哩(B站)热播,作者带着你学。

版权声明:本文内容引用自作者的图书《Python编程基础及应用》(高等教育出版社)。本文可以在互联网上转载传播,但必须包含文中的版权声明;本文不可以以纸质出版为目的进行摘抄或改编。

9.8 多态、抽象类

多态(polymorphism)是面向对象程序设计的一个重要概念,源自希腊语,意即“有多种形态”。对于程序设计而言,大致可以理解为:即使你不知道变量指向哪种形态,也能够对其执行操作,而且操作的行为将随对象的类型不同而不同。

对于Python程序员而言,可以不关心这个概念。因为在Python语言中,默认就是多态的。也就是说,对象被执行某个函数的时候,他的行为跟你想的多半是一样的。但作者认为,读者还是应该了解这个概念并理解其在程序设计中的重要性。

想象一个Word类软件,WPS或者Open Office之类,在文档中,用户会加入非常多的界面元素,包括但不限于:三角形、箭头、段落、圆形、矩形、艺术字、图片。对,就跟你想的一样,在面向对象程序设计中,这些元素都会使用类来描述,并且,设计者一定会为这些界面元素提供一个统一的父类。作者把这个类结构简化成下图的模样,读者要明白真实的情况比这个要复杂得多,但基本结构大体如此。


可以看到,所有的界面元素,三角形、圆形、... 、 文本段落(paragraph),被描述成拥有一个共同的祖先类-Shape。这个祖先类可以是抽象类,这意味着系统不允许你创建Shape类的对象,具体的稍后描述。抽象类什么具体的工作也不做,只是描述了他的全部后代的模样:至少实现draw()-描绘自身以及getSize()-返回元素在页面中的空间尺寸信息这两个方法。这种描述是强制性的,它的后代必须实现这两个方法或函数。

Triangle类用三个点坐标来描述自己的属性,除了实现必须的draw()和getSize()方法外,还实现了一个getArea()方法以计算自身所占面积。

Circle类则用一个圆点坐标以及一个半径来描述自己,也实现了额外的getArea()函数。

文本段落(Paragraph)类则用一个字符串sContent来存储其文本内容,另外,还额外实现了setFont()函数来设置文本的字体和字体大小。

作者把这4个类组织一个程序文件里,命名Shapes.py。首先,我们定义抽象基类Shape。

#Shapes.py
from abc import ABC, abstractmethod
class Shape(ABC):
    @abstractmethod
    def draw(self):
        pass

    @abstractmethod
    def getSize(self):
        pass

首先,我们从abc模块导入了ABC及abstractmethod。abc的意思作者猜应该是abstract base class - 抽象基类的首字母缩写。Shape被描述成ABC的子类,draw()函数以及getSize()函数都打上了@abstractmethod装饰符,这说明这两个函数为抽象函数。这种情况下,系统是不允许创建一个Shape对象的。这个抽象类存在的唯一意义就是规定了它的后代类的某些特征:必须实现 draw()及getSize()方法。

如果尝试实例化Shape, 比如s = Shape(),就会得到下述错误信息:

Traceback (most recent call last):
  File "D:/pylearn/C9_OOP/Shapes.py", line 11, in <module>
    s = Shape()
TypeError: Can't instantiate abstract class Shape with abstract methods draw, getSize

当且仅当Shape的某个后代类定义实现了Shape的全部抽象函数,该类才可以被实例化 - 即允许创建该类型的对象。下面是Triangle类、Circle类、Paragraph类的极简版本代码,注意,连同Shape类,这4个类都在同一个py文件中。

#Shapes.py
...
class Triangle(Shape):
    def __init__(self):
        self.point0 = (0,0)
        self.point1 = (0,0)
        self.point2 = (0,0)

    def draw(self):
        print("Triangle::draw")

    def getSize(self):
        pass       #detail omitted

    def getArea(self):
        return 0   #it should be w * h / 2
#Shapes.py
...
class Circle(Shape):
    def __init__(self):
        self.ptCenter = (0,0)
        self.iRadius = 0

    def draw(self):
        print("Circle::draw")

    def getSize(self):
        pass

    def getArea(self):
        return 0
#Shapes.py
...
class Paragraph(Shape):
    def __init__(self):
        self.sContent = ""

    def draw(self):
        print("Paragraph::draw")

    def getSize(self):
        pass

    def setFont(self,fontName,fontSize):
        pass

这三个类都实现了Shape抽象基类的全部抽象方法,都不再“抽象”,可以实例化。另外,我们还注意到这三个类的构造函数里都没有调用执行Shape类的构造函数,这里这样做是可以的,因为Shape类没有自定义构造函数,或者说Shape类的构造函数什么也没做。

让我们把关注点放在这三个类的draw()函数上。Office类软件会用文档来组织这些界面元素,在这里我们把这些界面元素想像成一个列表,在这个列表里包含了很多个三角形、矩形、段落、图片、艺术字、公式、图表对象,这些对象都是Shape类的子对象,都实现了draw()方法。

当一个页面被显示出来时,软件会遍历这个列表,然后逐一调用列表内Shape子对象的draw()方法,以便把每个界面元素画出来。对,你听得没错,就是每个对象自己画自己。因为三角形类了解三角形的数据表达形式,掌握描绘一个三角形的全部信息,由这个类的draw()来承担这个职责再合适不过了。圆形、段落这些类也是类似情况。我们设想一下,假设在页面上描绘三角形的任务不是由三角形类来完成,而是由外部代码来完成,那么外部代码就必须清楚并访问三角形对象内部的全部细节,如果这件事情真的发生的话,对于软件工程而言是灾难性的:外部代码知道太多关于三角形内部实现的细节! 内部实现的细节变成了接口的一部分! 三角形类接口不再简洁明了! 以后你如果想修改三角形的内部数据结构,这几乎不可能,因为外部代码也要跟着改,涉及的外部程序和修改点可能太多 --- 这种复杂的情况,我们称之为紧耦合 - tight coupling。而程序的松散耦合 - loose coupling,才是我们的目标。

#Shapes.py
...
t1 = Triangle()
t2 = Triangle()
c1 = Circle()
c2 = Circle()
p1 = Paragraph()

#doc模拟一个文档,将界面元素组织在列表中
doc = [p1,c2,t2,c1,t1]

#遍历全部界面元素,将它们全部画出来
def renderDocument(doc):
    for x in doc:
        x.draw()
renderDocument(doc)

执行结果

Paragraph::draw
Circle::draw
Triangle::draw
Circle::draw
Triangle::draw

在这段代码里,我们创建了两个三角形,两个圆形,一个段落 ,然后把它们放入一个列表中,这个列表就是一个文档的简化表达形式。renderDocument()函数遍历这个列表,逐一执行其元素的draw()方法。我们看到,renderDocument()函数并不清楚变量x的具体类型,它只认为x是一个Shape,实现了draw()方法,至于x到底是三角形、圆形或者别的什么界面元素,完全不关心。但是,我们发现,x是什么类型,就会执行什么类型的对应的draw()函数,并打印出对应的文字。这就是多态,这些变量类型未知,但自动展现出与类型对应的恰当行为。

作为初学者的你,看见这个觉得平淡无奇: 这不就是我想像的样子么! 是的,这正好说明Python语言的设计目标达到了,它几乎总是按你的设想来工作。但这样做是有代价的,代价之一就是执行效率低。在C++这种讲究效率的语言里,为了追求效率,多态不是默认的。

本节展示的类结构为程序的扩展提供了无限的可能及便利。如果Office软件试图建立一种全新的界面元素,比如某种直方图图表,软件设计者所要做的,就是继承Shape类并设计一个新的类,然后在新的类里实现全部抽象函数。然后,上述renderDocument()函数一个字符都不用修改,即可以拥抱新的界面元素的加入所带来的变化,以不变应万变!


相关推荐

大文件传不动?WinRAR/7-Zip 入门到高手,这 5 个技巧让你效率翻倍

“这200张照片怎么传给女儿?微信发不了,邮箱附件又超限……”62岁的张阿姨对着电脑犯愁时,儿子只用了3分钟就把照片压缩成一个文件,还教她:“以后用压缩软件,比打包行李还方便!”职场人更懂这...

电脑解压缩软件推荐——7-Zip:免费、高效、简洁的文件管理神器

在日常工作中,我们经常需要处理压缩文件。无论是下载软件包、接收文件,还是存储大量数据,压缩和解压缩文件都成为了我们日常操作的一部分。而说到压缩解压软件,7-Zip绝对是一个不可忽视的名字。今天,我就来...

设置了加密密码zip文件要如何打开?这几个方法可以试试~

Zip是一种常见的压缩格式文件,文件还可以设置密码保护。那设置了密码的Zip文件要如何打开呢?不清楚的小伙伴一起来看看吧。当我们知道密码想要打开带密码的Zip文件,我们需要用到适用于Zip格式的解压缩...

大文件想要传输成功,怎么把ZIP文件分卷压缩

不知道各位小伙伴有没有这样的烦恼,发送很大很大的压缩包会受到限制,为此,想要在压缩过程中将文件拆分为几个压缩包并且同时为所有压缩包设置加密应该如何设置?方法一:使用7-Zip免费且强大的文件管理工具7...

高效处理 RAR 分卷压缩包:合并解压操作全攻略

在文件传输和存储过程中,当遇到大文件时,我们常常会使用分卷压缩的方式将其拆分成多个较小的压缩包,方便存储和传输。RAR作为一种常见的压缩格式,分卷压缩包的使用频率也很高。但很多人在拿到RAR分卷...

2个方法教你如何删除ZIP压缩包密码

zip压缩包设置了加密密码,每次解压文件都需要输入密码才能够顺利解压出文件,当压缩包文件不再需要加密的时候,大家肯定想删除压缩包密码,或是忘记了压缩包密码,想要通过删除操作将压缩包密码删除,就能够顺利...

速转!漏洞预警丨压缩软件Winrar目录穿越漏洞

WinRAR是一款功能强大的压缩包管理器,它是档案工具RAR在Windows环境下的图形界面。该软件可用于备份数据,缩减电子邮件附件的大小,解压缩从Internet上下载的RAR、ZIP及其它类...

文件解压方法和工具分享_文件解压工具下载

压缩文件减少文件大小,降低文件失效的概率,总得来说好处很多。所以很多文件我们下载下来都是压缩软件,很多小伙伴不知道怎么解压,或者不知道什么工具更好,所以今天做了文件解压方法和工具的分享给大家。一、解压...

[python]《Python编程快速上手:让繁琐工作自动化》学习笔记3

1.组织文件笔记(第9章)(代码下载)1.1文件与文件路径通过importshutil调用shutil模块操作目录,shutil模块能够在Python程序中实现文件复制、移动、改名和删除;同时...

Python内置tarfile模块:读写 tar 归档文件详解

一、学习目标1.1学习目标掌握Python内置模块tarfile的核心功能,包括:理解tar归档文件的原理与常见压缩格式(gzip/bz2/lzma)掌握tar文件的读写操作(创建、解压、查看、过滤...

使用python展开tar包_python拓展

类Unix的系统,打包文件经常使用的就是tar包,结合zip工具,可以方便的打包并解压。在python的标准库里面有tarfile库,可以方便实现生成了展开tar包。使用这个库最大的好处,可能就在于不...

银狐钓鱼再升级:白文件脚本化实现GO语言后门持久驻留

近期,火绒威胁情报中心监测到一批相对更为活跃的“银狐”系列变种木马。火绒安全工程师第一时间获取样本并进行分析。分析发现,该样本通过阿里云存储桶下发恶意文件,采用AppDomainManager进行白利...

ZIP文件怎么打开?2个简单方法教你轻松搞定!

在日常工作和生活中,我们经常会遇到各种压缩文件,其中最常见的格式之一就是ZIP。ZIP文件通过压缩数据来减少文件大小,方便我们进行存储和传输。然而,对于初学者来说,如何打开ZIP文件可能会成为一个小小...

Ubuntu—解压多个zip压缩文件.zip .z01 .z02

方法将所有zip文件放在同一目录中:zip_file.z01,zip_file.z02,zip_file.z03,...,zip_file.zip。在Zip3.0版本及以上,使用下列命令:将所有zi...

如何使用7-Zip对文件进行加密压缩

7-Zip是一款开源的文件归档工具,支持多种压缩格式,并提供了对压缩文件进行加密的功能。使用7-Zip可以轻松创建和解压.7z、.zip等格式的压缩文件,并且可以通过设置密码来保护压缩包中的...

取消回复欢迎 发表评论: