python中的类与对象(1)

news2024/11/20 11:37:54

目录

一. 引子:模板

二. 面向过程与面向对象

(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 data

dog1 = 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"] = 15
    return data

def person(name,age):  # 人的属性模板
    data = {
        "name":name,
        "age":age,
        "life_val":100,  # 设置为默认值
    }
    if age > 18:  # 根据人的年龄推算战斗力
        data["attack_val"] = 50  
    else:
        data["attack_val"] = 30
    return data

dog1 = 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"] = 15
    def bite(person):  # 狗咬人
        person["life_val"] -= data["attack_val"]
        print("狗[%s]咬了[%s]人一口,人的剩余血量是[%s]"%(data["name"],person["name"],person["life_val"]))
    data["bite"] = bite  # 为了在函数外部调用此方法
    return data

def person(name,age):  # 人的属性模板
    data = {
        "name":name,
        "age":age,
        "life_val":100,  # 设置为默认值
    }
    if age > 18:  # 根据人的年龄推算战斗力
        data["attack_val"] = 50  
    else:
        data["attack_val"] = 30
    def beat(dog):  # 人打狗
        dog["life_val"] -= data["attack_val"]
        print("人[%s]揍了[%s]狗一下,狗的剩余血量是[%s]"%(data["name"],dog["name"],dog["life_val"]))
    data["beat"] = beat  # 为了在函数外部调用此方法
    return data

dog1 = 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.coloradmin.cn/o/1469272.html

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

相关文章

互联网加竞赛 机器视觉opencv答题卡识别系统

0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 答题卡识别系统 - opencv python 图像识别 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🥇学长这里给一个题目综合评分(每项满分5分…

【k8s资源调度-HPA(自动扩缩容)】

1、HPA可以做什么? 通过观察pod的cpu、内存使用率或自定义metrics指标进行自动的扩容或缩容pod的数量。通常用于Deployment,不适用于无法扩/缩容的对象,如DaemonSet。控制管理器每隔30s(可以通过-horizontal-pod-autoscaler–sync-period修改…

TensorRT及CUDA自学笔记003 NVCC及其命令行参数

TensorRT及CUDA自学笔记003 NVCC及其命令行参数 各位大佬,这是我的自学笔记,如有错误请指正,也欢迎在评论区学习交流,谢谢! NVCC是一种编译器,基于一些命令行参数可以将使用PTX或C语言编写的代码编译成可…

STL容器之list

​ 1.封装除了对数据的保护、更好地管理数据之外,还有实现了对上层的统一; ​ 2.类模板参数的不同,一方面是为了实例化出来不同的类,另一方面是为了实现类的成员函数的不同; 一、认识list ​ 1.list是一种带头双向循…

软件实例,物流货运配货单打印模板软件单据打印查询管理系统软件教程,可以同时打印标签或补打

软件实例,物流货运配货单打印模板软件单据打印查询管理系统软件教程,可以同时打印标签或补打 一、前言 以下软件教程以 佳易王物流单打印查询系统V17.1为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 这个版本在原来基…

opencv绘制基本图形,在图片上添加文字

文章目录 1.opencv绘制基本图形1. 画直线, cv2.line( )2. 画长方形,cv2.rectangle( )3. 画圆型,cv2.circle( )4. 画折线,cv2.polylines( ) 2.图片上显示文字 本章主要阐述利用opencv绘制一些常见的图形方法和技巧,以及…

2024年贵州省事业单位考试下周一开始报名,千万不要错过报名时间

2024年贵州省事业单位考试公告已出!快看看你能不能报名! 1、报名时间安排 (一)网上报名 2024年2月26日-2024年2月28日 (二)网上资格初审 2024年2月26日-2024年2月29日 (三)网上缴费 2024年2月26日-2024年3月1日 2、笔试安排 2024年3月30日 08:30-10:…

HDL FPGA 学习 - FPGA基本要素,开发流程,Verilog语法和规范、编写技巧

目录 Altera FPGA 基本要素 FPGA 开发流程和适用范围 设计和实施规范 顶层设计的要点 Verilog HDL 语法规范 编写规范 设计技巧 编辑整理 by Staok,始于 2021.2 且无终稿。转载请注明作者及出处。整理不易,请多支持。 本文件是“瞰百易”计划的…

如何正确设置CrossOver之偏好设置 crossover软件使用 crossover设定 crossover软件安装

CrossOver的核心是Wine,Wine是一个能在多种POSIX-compliant操作系统(如:Linux、Mac OS等)上运行Windows应用的兼容层。Wine不是Windows的模拟工具,它是把Windows API 调用翻译成为动态的 POSIX 调用,实现Li…

东方博宜 1086. 姐妹数对

东方博宜 1086. 姐妹数对 思路&#xff1a;先按照题意把规律找出来&#xff0c;按照规律再写程序。 #include<iostream> using namespace std; int main() {int n ;cin >> n ;int sum 0 ;for(int i 1 ; i < n ; i){for(int j i1 ; j < n ; j){int m ;m …

Linux配置jdk、tomcat、mysql离线安装与启动

目录 1.jdk安装 2.tomcat的安装&#xff08;开机自启动&#xff09; 3.MySQL的安装 4.连接项目 1.jdk安装 上传jdk安装包 jdk-8u151-linux-x64.tar.gz 进入opt目录&#xff0c;将安装包拖进去 解压安装包 这里需要解压到usr/local目录下&#xff0c;在这里我新建一个文件夹…

Git的基本操作和原理

目录 写在前面的话 为什么要有Git&#xff08;git初识&#xff09;&#xff1f; Git安装(Centos为例) Git基本操作 创建Git本地仓库 Git配置 认识工作区、暂存区、版本库 概念认识 添加文件 查看.git文件 修改文件 版本回退 撤销修改 情况一&#xff1a;…

【办公类-22-06】周计划系列(1)“信息窗” (2024年调整版本)

作品展示 调用原来的信息窗素材&#xff0c;制作下学期的19周的信息窗基础word 背景需求&#xff1a; 开学了&#xff0c;继续做周计划系列&#xff0c;在原有基础上&#xff0c;进行进一步代码优化 【办公类-22-01】周计划系列&#xff08;1&#xff09;-生成“信息窗”&am…

供应链大数据:穿越经济迷雾的指南针

随着经济形势的变幻莫测&#xff0c;企业运营面临着前所未有的挑战。在这个充满不确定性的时代&#xff0c;供应链大数据如同一盏明亮的指南针&#xff0c;为企业提供精准的方向指引。下面&#xff0c;我们将深入探讨供应链大数据如何帮助企业洞察市场趋势、优化库存管理、降低…

K线实战分析系列之八:十字星——容易识别的特殊形态

K线实战分析系列之八&#xff1a;十字星——容易识别的特殊形态 一、十字启明星和十字黄昏星二、弃婴底部形态和弃婴顶部形态三、总结十字启明星和十字黄昏星形态的要点 一、十字启明星和十字黄昏星 当开盘价与收盘价极为接近的时候&#xff0c;当期的K线就呈现为一根十字线&am…

PyPDF2:项目实战源码分享(PDF裁剪)

目录&#x1f4d1; 1. 背景&#x1f4d1;2. 源码模块解析&#x1f4d1;2.1 读取PDF页数2.2 获取指定页的宽高尺寸2.3 裁剪单页PDF2.4 批量裁剪PDF 总结&#x1f4d1; 1. 背景&#x1f4d1; 接PyPDF2模块推荐博文中提到的实际需求&#xff08;将银行网站下载来的多页且单页多张…

设计模式--单例模式--懒汉饿汉

单例模式 单例模式(Singleton)&#xff0c;保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。 单例模式 通常我们可以让一个全局变量使得一个对象被访问&#xff0c;但它不能防止你实例化多个对象。一个最好的办法就是&#xff0c;让类自身负责保存它的唯一实…

[嵌入式系统-34]:RT-Thread -19- 新手指南:RT-Thread标准版系统架构

目录 一、RT-Thread 简介 二、RT-Thread 概述 三、许可协议 四、RT-Thread 的架构 4.1 内核层&#xff1a; 4.2 组件与服务层&#xff1a; 4.3 RT-Thread 软件包&#xff1a; 一、RT-Thread 简介 作为一名 RTOS 的初学者&#xff0c;也许你对 RT-Thread 还比较陌生。然…

vue-element-admin如何绕开系统的请求的路由,使用静态路由

我开发时候遇到一个这样的问题&#xff0c;服务端权限管理部分还没搞好&#xff0c;所以但是需要将所有菜单列出来 我做了以下的修改 首先是建一个文件存放后期需要动态生成的路由 引入到常量路由中 另外在permissions当中

FPGA之16:1复选器

每个slice 都有一个F8MUX。F8MUX原语&#xff1a; MUXF8 MUXF8_inst&#xff08; .0&#xff08;0&#xff09;&#xff0c;Il Output of MUX to general routing .I0&#xff08;10&#xff09;&#xff0c;//Input&#xff08;tie to MUXF7L/LO out&#xff09; .I1&#xf…