python中的类与对象(1)

目录

一. 引子:模板

二. 面向过程与面向对象

(1)面向过程编程

(2)面向对象编程

三. 对象与类

(1)对象

(2)类

四. 面向对象程序设计的特点:封装,继承,多态

(1)封装

(2)继承

(3)多态


一. 引子:模板

设想我们现在编写一款人狗大战的游戏。在人狗大战中,我们首先要描述狗和人。例如,对于一条狗来说,它有姓名,品种,狗的攻击力等等。我们可以用字典中的键值对去表示它的属性:

dog1 = {"name":"zhaopeng",  # 姓名"d_type":"二哈",  # 品种"attack_val":30,  # 攻击值"life_val":50,  # 生命值
}print(dog1)  
# {'name': 'zhaopeng', 'd_type': '二哈', 'attack_val': 30, 'life_val': 50}

为了方便复用,我们可以把它写成函数,这样每次传入参数即可:

def dog(name,d_type,attack_val):  # 模板data = {"name":name,"d_type":d_type,"attack_val":attack_val,"life_val":100,  # 设置为默认值}return datadog1 = dog("zhaopeng","二哈",30)  # 生成实体
dog2 = dog("zhangsan","藏獒",50)
print(dog1, dog2)  
# {'name': 'zhaopeng', 'd_type': '二哈', 'attack_val': 30, 'life_val': 100} 
# {'name': 'zhangsan', 'd_type': '藏獒', 'attack_val': 50, 'life_val': 100}

同理我们可以写出人的属性模板。此外,我们还可以继续复杂化这个函数。例如我们可以把狗的品种和攻击力建立一个一一对应的联系,把人的年龄和攻击力也建立一个一一对应的关系:

# 将狗的品种与攻击值建立联系
attack_val = {"二哈":20,"藏獒":40,"小奶狗":5
}def dog(name,d_type):  # 狗的属性模板data = {"name":name,"d_type":d_type,"life_val":100,  # 设置为默认值}if d_type in attack_val:data["attack_val"] = attack_val[d_type]  # 在attack_val字典中查询键值对else:data["attack_val"] = 15return datadef person(name,age):  # 人的属性模板data = {"name":name,"age":age,"life_val":100,  # 设置为默认值}if age > 18:  # 根据人的年龄推算战斗力data["attack_val"] = 50  else:data["attack_val"] = 30return datadog1 = dog("zhaopeng","二哈")  # 生成狗实体
dog2 = dog("zhangsan","藏獒")
person1 = person("lisi",30)  # 生成人实体
person2 = person("wangwu",15)
print(dog1, dog2) 
# {'name': 'zhaopeng', 'd_type': '二哈', 'life_val': 100, 'attack_val': 20} 
# {'name': 'zhangsan', 'd_type': '藏獒', 'life_val': 100, 'attack_val': 40}
print(person1, person2)
# {'name': 'lisi', 'age': 30, 'life_val': 100, 'attack_val': 50} 
# {'name': 'wangwu', 'age': 15, 'life_val': 100, 'attack_val': 30}

现在我们编写狗咬人和人咬狗的函数来模拟它们互相攻击:

def bite(dog, person):  # 狗咬人person["life_val"] -= dog["attack_val"]print("狗[%s]咬了[%s]人一口,人的剩余血量是[%s]"%(dog["name"],person["name"],person["life_val"]))
def beat(dog, person):  # 人打狗dog["life_val"] -= person["attack_val"]print("人[%s]揍了[%s]狗一下,狗的剩余血量是[%s]"%(person["name"],dog["name"],dog["life_val"]))bite(dog1, person1)
# 狗[zhaopeng]咬了[lisi]人一口,人的剩余血量是[80]
beat(dog1, person2)
# 人[wangwu]揍了[zhaopeng]狗一下,狗的剩余血量是[70]

这样写当然看起来没有问题,然而我们如果不小心写反了人和狗,例如:

bite(person1, dog1)

这个时候自然会出现问题。我们希望实现bite函数只能是“狗咬人”,beat函数只能是“人打狗”。我们希望给人和狗增加对应的动作。当然,我们可以在函数体里面增加if...else判断语句,但当游戏动作变的很多的时候这种方法也不好。我们可以把bite函数和beat函数内嵌到人和狗的属性里面:

def dog(name,d_type):  # 狗的属性模板data = {"name":name,"d_type":d_type,"life_val":100,  # 设置为默认值}if d_type in attack_val:data["attack_val"] = attack_val[d_type]  # 在attack_val字典中查询键值对else:data["attack_val"] = 15def bite(person):  # 狗咬人person["life_val"] -= data["attack_val"]print("狗[%s]咬了[%s]人一口,人的剩余血量是[%s]"%(data["name"],person["name"],person["life_val"]))data["bite"] = bite  # 为了在函数外部调用此方法return datadef person(name,age):  # 人的属性模板data = {"name":name,"age":age,"life_val":100,  # 设置为默认值}if age > 18:  # 根据人的年龄推算战斗力data["attack_val"] = 50  else:data["attack_val"] = 30def beat(dog):  # 人打狗dog["life_val"] -= data["attack_val"]print("人[%s]揍了[%s]狗一下,狗的剩余血量是[%s]"%(data["name"],dog["name"],dog["life_val"]))data["beat"] = beat  # 为了在函数外部调用此方法return datadog1 = dog("zhaopeng","二哈")  # 生成狗实体
dog2 = dog("zhangsan","藏獒")
person1 = person("lisi",30)  # 生成人实体
person2 = person("wangwu",15)dog1["bite"](person1)  # 狗[zhaopeng]咬了[lisi]人一口,人的剩余血量是[80]
person2["beat"](dog1)  # 人[wangwu]揍了[zhaopeng]狗一下,狗的剩余血量是[70]
dog2["beat"](person1)  # KeyError: 'beat'

这样,我们就实现了限制人只能用人自己的功能,狗只能用狗自己的功能啦。

说了这么多,这跟面向对象有什么关系么? 当然有,其实你上面写的代码,就是面向对象的代码。你在设计角色时,为了让一个角色可以变成多个实体对象,你设计了一个基础模板,只要传入不同参数,就会产生不同的狗。这代表你已经开始切换成上帝视角看事情,上帝视角就是面向对象编程的视角,上帝要造世界万物,他肯定不是一个一个的造出来,他肯定是设计出一个个的物种的模板,然后通过模子批量批一个个的实体造出来。造出来的实体各有特色,属性、功能都不尽相同,有的人的贪婪、有的人好色、有的人懦弱,有的人勇猛。这些人之间会发生什么关系,谁和谁打仗,上帝懒的管,上帝只控制大局。我们接下来一点点接晓怎么通过面向对象在编程世界里做上帝。

二. 面向过程与面向对象

在介绍面向过程与面向对象之前,先介绍一下什么是编程范式:

编程是程序员用特定的语法+数据结构+算法组成的代码来告诉计算机如何执行任务的过程,一个程序是程序员为了得到一个任务结果而编写的一组指令的集合。正所谓条条大路通罗马,实现一个任务的方式有很多种不同的方式,对这些不同的编程方式的特点进行归纳总结出来的编程方式类别,即为编程范式。

不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路,大多数语言只支持一种编程范式,当然也有些语言可以同时支持多种编程范式。 两种最重要的编程范式分别是面向过程遍程和面向对象编程。

(1)面向过程编程

Procedural programming uses a list of instructions to tell the computer what to do step-by-step.面向过程编程依赖procedures。一个procedure包含一组要被进行计算的步骤,面向过程又被称为top-down languages,就是程序从上到下一步步执行,从头到尾的解决问题。

面向过程的基本设计思路就是程序一开始是要着手解决一个大的问题,然后把一个大问题分解成很多个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决。

举个典型的面向过程的例子,把大象装冰箱,整个流程分以下几步:

  • 把冰箱门打开,open()
  • 把大象装入冰箱,push()
  • 把冰箱门关上,close()

我们只需要编写每一步的代码,然后连起来即可。然而,这样做的问题也是显而易见的,就是如果你要对程序进行修改,对你修改的那部分有依赖的各个部分你都也要跟着修改。举个例子,现在要编写:

  • 把老虎装进冰箱
  • 把大象装进皮箱
  • 把老虎装进冰箱,但不关冰箱门

如果程序开头设置了一个变量值为1,但如果其它子过程依赖这个值为1的变量才能正常运行,如果修改了这个变量,那这个子过程你也要修改,假如又有一个其它子程序依赖这个子过程,那就会发生一连串的影响,随着程序项目越来越大,这种编程方式的维护难度会越来越高。

所以我们一般认为, 如果你只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,但如果你要处理的任务是复杂的,且需要不断选代和维护的,那还是用面向对象最方便了。

(2)面向对象编程

同样是上面的问题,我们抽象出来两个类:

  • 冰箱类,它具有open()和close()方法
  • 大象类,它具有走进冰箱的enter()方法

这样每次修改需求,就只需重新把类具象化即可。例如仍然对于大象装冰箱的问题可以写成:

  • 冰箱.open()
  • 大象.enter()
  • 冰箱.close()

如果修改需求为老虎装冰箱,则第二行修改为老虎.enter()即可。

以上程序设计方法就是面向对象的程序设计。面向对象(object oriented)的英文缩写是OO,它是一种设计思想。从20世纪60年代提出面向对象的概念到现在,它已经发展成为一种比较成熟的编程思想,并且逐步成为当前软件开发领域的主流技术。如我们经常听说的面向对象编程(object oriented prgramming,OOP)就是主要针对大型软件设计而提出的,它可以使软件设计更加灵活,并且能更好地进行代码复用。

面向对象中的对象(object),通常是指客观世界中存在的对象。这个对象具有唯一性,对象之间各不相同,各有各的特点,每个对象都有自己的运动规律和内部状态;对象之间又是可以相互联系相互作用的。另外,对象也可以是一个抽象的事物。例如,可以从圆形、正方形、三角形等图形抽象出一个简单图形,简单图形就是一个对象,它有自己的属性和行为,图形中边的个数是它的属性,图形的面积也是它的属性,输出图形的面积就是它的行为。概括地讲,面向对象技术是一种从组织结构上模拟客观世界的方法。

三. 对象与类

(1)对象

对象是一种抽象概念,表示任意存在的事物。世间万物皆对象。现实世界中,随处可见的一个事物就是对象,对象是事物存在的实体。如上面引子里面提到的狗。通常将对象划分为两部分,即静态部分与动态部分。静态部分被称为“属性”,任何对象都具备自身属性,这些属性不仅是客观存在的,而且是不能被忽视的,如狗的名字,品种,初始血值,攻击力等。动态部分指的是对象的行为,即对象执行的动作,如在人狗大战中狗可以咬人。

在Python中,一切都是对象。也就是说,不仅是具体的事物被称为对象,字符串、函数等也都被称为对象。这说明Python天生就是面向对象的。

(2)类

类是封装对象的属性和行为的载体,反过来说,具有相同属性和行为的一类实体被称为类。例如,和雁群比作大雁类,那么大雁类就具备了喙、翅膀和爪等属性,觅食、飞行和睡觉等行为,而一只要从北方飞往南方的大雁则被视为大雁类的一个对象。

再例如引子中的人狗大战,狗类具有姓名,品种,初始血值,攻击力等属性,咬人的行为;一只具体的狗

{'name': 'zhaopeng', 'd_type': '二哈', 'life_val': 100, 'attack_val': 20} 

被视为狗类的一个对象。

四. 面向对象程序设计的特点:封装,继承,多态

(1)封装

封装是面向对象编程的核心思想,将对象的属性和行为封装起来,而将对象的属性和行为封装起来的载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。例如,用户使用计算机,只需要按键盘就可以实现一些功能,而无须知道计算机内部是如何工作的。

采用封装思想保证了类内部数据结构的完整性,使用该类的用户不能直接看到类中的数据结构,而只能执行类允许公开的数据,这样就避免了外部对内部数据的影响,提高了程序的可维护性。

(2)继承

矩形、菱形、平行四边形和梯形等都是四边形。因为四边形与它们具有共同的特征,即拥有4个边。只要将四边形适当地延伸,就会得到上述图形。以平行四边形为例,如果把平行四边形看作四边形的延伸,那么平行四边形就复用了四边形的属性和行为,同时添加了平行四边形特有的属性和行为如平行四边形的对边平行且相等。

其中将类似于平行四边形的类称为子类,将类似于四边形的类称为父类或超类。值得注意的是,在述平行四边形和四边形的关系时,可以说平行四边形是特殊的四边形,但不能说四边形是平行四边形。同理,Python中可以说子类的实例都是父类的实例,但不能说父类的实例是子类的实例

综上所述,继承是实现代码重复利用的重要手段,子类通过继承复用了父类的属性和行为的同时,又添加了子类特有的属性和行为。

(3)多态

将父类对象应用于子类的特征就是多态。例如,创建一个螺丝类,螺丝类有两个属性,即螺丝粗细和螺纹密度。然后创建两个类,即一个长螺丝类和一个短螺丝类,并且它们都继承了螺丝类。这样长螺丝类和短螺丝类不仅具有相同的特征(螺丝粗细相同,且螺纹密度也相同),而且还具有不同的特征(一个长,一个短)。综上,一个螺丝类衍生出不同的子类,子类继承父类特征的同时也具备了自己的特征,并且能实现不同的效果。

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

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

相关文章

【C语言】linux内核ipoib模块 - ipoib_ib_handle_rx_wc

一、中文注释 // 定义一个处理InfiniBand接收完成工作请求的函数 static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) {// 通过网络设备获取私有数据结构struct ipoib_dev_priv *priv ipoib_priv(dev);// 获取工作请求ID,并屏蔽掉接收…

探索未来:Web3如何改变我们的生活方式

在数字化的时代,技术的不断发展和创新已经成为了我们生活的常态。而在这个不断变革的过程中,区块链技术作为一种颠覆性的技术,正逐渐成为人们关注的焦点。作为区块链技术的下一代,Web3正日益崭露头角,成为了未来的发展…

橘子学es原理01之准备工作

es本身是具备很好的使用特性的,我指的是他的部署方面的,至于后期的使用和运维那还是很一眼难尽的。 我们从这一篇开始就着重于es的一些原理性的的一些探讨,当然我们也会有一些操作性的,业务性的会分为多个栏目来写。比如前面我写的…

Flutter开发进阶之Package

Flutter开发进阶之Package 通常我们在Flutter开发中需要将部分功能与整体项目隔离,一般有两种方案Plugin和Package,Application是作为主体项目,Module是作为原生项目接入Flutter模块。 当独立模块不需要与原生项目通讯只需要Plugin就可以&a…

【广度优先搜索】【网格】【割点】1263. 推箱子

作者推荐 视频算法专题 涉及知识点 广度优先搜索 网格 割点 并集查找 LeetCode:1263. 推箱子 「推箱子」是一款风靡全球的益智小游戏,玩家需要将箱子推到仓库中的目标位置。 游戏地图用大小为 m x n 的网格 grid 表示,其中每个元素可以是墙、地板或…

利用LaTex批量将eps转pdf、png转eps、eps转png、eps转svg、pdf转eps

1、eps转pdf 直接使用epstopdf命令(texlive、mitex自带)。 在cmd中进入到eps矢量图片的目录,使用下面的命令: for %f in (*.eps) do epstopdf "%f" 下面是plt保存eps代码: import matplotlib.pyplot as…

计算机网络面经-TCP的拥塞控制

写在前边 前边我们分享了网络分层协议、TCP 三次握手、TCP 四次分手。今天我们继续深入分享一下 TCP 中的拥塞控制。 对于 TCP 的拥塞控制,里边设计到很多细节,平平无奇的羊希望通过这一节能够将这部分内容串通起来,能够让你更深刻的记忆这部分内容。 思维导图 1、什么…

封装(encapsulation)

封装[encapsulation] 封装介绍封装好处封装的实现步骤(三步)入门案例封装与构造器 封装介绍 封装就是把抽象的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],…

vue项目的前端工程化思路webpack(持续更新中)

写在前面:现在的前端网页功能丰富,特别是SPA(single page web application 单页应用)技术流行后,JavaScript的复杂度增加和需要一大堆依赖包,还需要解决Scss,Less……新增样式的扩展写法的编译工…

DC与DCT DCG的区别

先进工艺不再wire load model进行静态时序分析,否则综合结果与后端物理电路差距很大,因此DC综合工具也进行了多次迭代,DC工具有两种模式,包括wire load mode和Topographical Mode,也就是对应的DC Expert和DC Ultra。 …

unity hub (第一部)初学配置

1、安装Unity Hub 2、设置中文 3、安装编辑器 4、新建项目 5、新建完成后进入编辑器 6、 编辑器设置中文 editPreferencesLanguages选择中文

机器学习基础(五)监督与非监督学习的结合

导语:上一节我们详细探索非监督学习的进阶应用,详情可见: 机器学习基础(四)非监督学习的进阶探索-CSDN博客文章浏览阅读613次,点赞15次,收藏13次。非监督学习像一位探险家,挖掘未标…

电路设计(25)——4位数字频率计的multisim仿真及PCB设计

1.设计要求 使用4位数码管,显示输入信号的频率。完成功能仿真后,用AD软件,画出原理图以及PCB。 2.电路设计 输入信号的参数为: 可见,输入为168HZ,测量值为170HZ,误差在可接受的范围内。 3.PCB设…

Bluesky数据采集框架-2

访问保存的数据 到此,自然想到了"我如何访问我保存的数据?"。从bluesky的视角,那真的不是bluesky的关注,但它是一个合理的问题,因此我们将强调一个特定的场景。 注意:本章假设你正在使用databr…

AI:134-基于深度学习的社交媒体图像内容分析

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的关键代码,详细讲解供…

C语言——实用调试技巧——第2篇——(第23篇)

坚持就是胜利 文章目录 一、实例二、如何写出好(易于调试)的代码1、优秀的代码2、示范(1)模拟 strcpy 函数方法一:方法二:方法三:有弊端方法四:对方法三进行优化assert 的使用 方法五…

Spring之AOP源码解析(下)

前言 在上一遍文章中,我们主要讲解了ProxyFactory在Spring完成AOP动态代理的过程中发挥的作用。这一篇我们主要讲解这些注解都是如何注入Advisors,然后分析这些Advisors生效的条件 注解都是如何注入Advisor并匹配的 EnableTransactionManagement注解 我们在之前提到EnableT…

STM32 TCP实现OTA

芯片:stm32f407 开发平台:stm32cubeide 上位机开发平台:visual studio 2017 1. FLASH分配 将flash划分为四个部分: bootloader: 0x8000000-0x800ffff app1: 0x8010000-0x805ffff app2: …

一流的财务:搞数据!!!(干货)

“三流财务给数据,二流财务给分析报告,一流财务给....(解决方案)“这些文章应该很多人都看到过,这个口号粗看好像很有道理,但笔者并不认同,因为大家都忽略了一个重要的概念:数据&…

什么是rouge metric

采用分类任务的指标评估生成任务的问题 举个例子,在一个seq2seq模型中,黄金标签是“police killed the gunman”,模型输出是"the gunman police killed",两句话的意思是有差别的,但是从unigram的角度&#…