6.1 Python面向对象设计及应用

news2024/9/29 3:34:13

1 类和对象

对象是具有某些特性和功能的具体事物的抽象。每个对象都具有描述其特征的属性及附属于它的行为。如:一个人有姓名、性别、身高、体重等特征描述,也有走路、说话、学习、开车等行为。
每个对象都有一个类,类是创建对象实例的模板,是对对象的抽象和概括,它包含对所创建对象的属性描述和行为特征的定义。如:我们在马路上看到的汽车都是一个个的汽车对象,它们都属于汽车类。

面向对象的其它重要概念:

  • 封装
  • 继承
  • 多态
  • 对基类方法的覆盖或重写。

2 定义和使用类

2.1 类定义

创建类的语法为:

class 类名:
	属性(成员变量)
	属性
	...
	成员函数(成员方法)
	...

例如,定义一个Person类:

class Person:
	num = 1					#成员变量
	def SayHello(self):		#成员函数
		print("Hello!")

2.2 对象定义

对象是类的实例。如果人类是一个类的话,那么某个具体的人就是一个对象。只有定义了具体的对象,才可以通过“对象名.成员”的方式来访问其中的数据成员或成员函数。
创建对象的语法为:

对象名 = 类名()

例如,下面的代码定义了一个类Person的对象p:

p = Person()
p.SayHello() 	#访问成员函数SayHello()

3 属性和方法

属性:
  公有属性 (属于类,每个类一份)
  普通属性 (属于对象,每个对象一份)
  私有属性 (属于对象,跟普通属性相似,只是不能通过对象直接访问)
方法:(按作用)
  构造方法
  析构函数
方法:(按类型)
  普通方法
  私有方法(方法前面加两个下划线)
  静态方法
  类方法
  属性方法

3.1 构造函数__init__

  • 方法__init__()又被称为构造器(constructor)或构造函数;
  • 用__init__()这个特殊的方法(函数)可以方便地自己对类的属性进行定义;
  • 定义完init()方法后,创建的每个实例都有自己的属性,也方便直接调用类中的函数
  • 成员函数需要被手动调用,而构造函数在创建对象的过程中是自动被调用的。
class Box:
    def  __init__(self, width, height, depth):  #这里的init函数就相当于跟类同名的函数,即指代类Box本身实例化了一个具体的Box
        self.width = width
        self.height = height
        self.depth = depth
 
    def getVolume(self):
        return self.width * self.height * self.depth
 
b = Box(10, 20, 30)  #构造函数在创建对象的过程中是自动被调用的,
print(b.getVolume())

3.2 析构函数

析构函数__del__(self): 在程序结束时自动执行,如果程序没有结束,那么析构函数函数里面的代码不会执行。
执行时间:

  1. 如果该函数在class里面,那么类里面的方法运行完毕,就会自动执行析构函数函数的代码;
  2. 手动删除:del+变量名 删除之后不能再次使用。

例如:

class Box:
    def  __init__(self, width, height, depth):  #这里的init函数就相当于跟类同名的函数,即指代类Box本身实例化了一个具体的Box
        self.width = width
        self.height = height
        self.depth = depth
    
    def __del__(self):
    	print("Box's object is not existed!")
 
    def getVolume(self):
        return self.width * self.height * self.depth
 
b = Box(10, 20, 30)  # 构造函数在创建对象的过程中是自动被调用的,
print(b.getVolume())
print(b)
del b				#删除b对象变量

3.3 类属性和实例属性

  • 类属性是在类中定义的属性,它是和这个类所绑定的,这个类中的所有对象都可以访问。访问时可以通过类名来访问,也可以通过实例名来访问。
  • 实例属性是与类的实例相关联的数据值,是这个实例私有的,只有这个对象自己可以访问。当一个实例被释放后,它的属性同时也被清除了。

例1:

# 定义了类之后,Python就会为类分配一块内存空间,里面放它的相关属性和方法。
# 这里在类中定一个了一个类属性,相当于在Person类的内存空间中有了值为10的age属性。
class Person():
    age = 10
 
# 给类名加上函数调用符号,就相当于创建了一个对象。
# 现在我们分别创建了一个叫沈腾的人和一个叫马丽的人。
# 创建后,Python也会为对象分别分配内存空间
st = Person()  
ml = Person()
 
# 使用对象访问类属性,它会先去对象的内存空间里面找age属性,如果没有,就向上找对象所属类的内存空间。
# 而在这里它并不是直接取了对象的内存空间的age属性,因为此时对象的内存空间里面还没有age属性。
# 这里实际上是对象访问了类的内存空间,从类内存空间中取出来age属性的值,并打印出来
# 所以这里沈腾对象属性值和马丽对象属性值都是类属性值10
print("st对象:%s" % st.age)  
print("ml对象:%s" % ml.age)
 
 # 要记住一点,只要给对象有了赋值操作,那么就相当于给对象的内存空间中动态创建了一个属性,所以这里此时沈腾对象的内存空间中有了一个age属性了,是属于这个对象的属性,也就是我们所说的实例属性。
 # 那么此时st.age会先在对象内存空间中找age属性,找到了,就不会再去类内存空间中找,所以此时st.age访问的是对象内存空间的age属性。
 # 所以此时沈腾对象属性值是沈腾对象内存空间age属性的值,也就是12。而非类属性值10。
st.age = 12 
print("st对象:%s" % st.age)
 
# 因为马丽对象还没有进行赋值操作,所以它还没有在它自己的内存空间中动态创建age属性。所以它这里访问的依旧是类内存空间中的age属性值。
# 而上述语句改变的是沈腾内存空间中age的值,所以不会影响到马丽对象属性值。
# 这里打印马丽对象属性值也就是类的属性值10。
print("ml对象:%s" % ml.age) 
 
# 因为上面的赋值语句改变的是对象的内存空间,所以类属性的值其实并没有改变,依旧是原来的值10。
print("类属性值:%s" % Person.age)  
 

根据运行结果分析如下:

  • 在没有st.age没有执行之前的打印值都是类属性的值10,而st.age=12执行后,st.age值就变成了12;
  • ml.age和Person.age都没有变,依旧是类属性的10。
    在这里插入图片描述

例2:可以在类的构造方法__init__中对对象的属性进行初始化,这里也是相当于对对象的属性进行了赋值操作,所以也是在对象的内存空间中动态的创建了实例属性。因为self参数就相当于对象自己,self.age在对象创建后就相当于对象.age,如st.age,ml.age,和上面例子原理是一样的。

class Person():
    age = 10
    def __init__(self, age):
        self.age = age
 
 
# 因为在构造方法中就已经给self.age属性赋值了。
# 所以创建对象时,沈腾对象内存空间中和马丽对象内存空间中就都有了age属性,这是属于对象的属性。
# 所以以后在使用st.age和ml.age时,访问到的都是对象内存空间中的age值了。
st = Person(18)  
ml = Person(9)
 
# 这里就访问的是对象内存空间中的age属性值了
# 所以分别打印18和9
print("st对象:%s" % st.age)  
print("ml对象:%s" % ml.age)
 
# 这里给沈腾对象的age属性重新赋值,改变的也仅是沈腾对象内存空间中的age属性值
# 不会改变马丽对象内存空间age属性值和类内存空间age属性值。
st.age = 12  
print("st对象:%s" % st.age)
print("ml对象:%s" % ml.age) 
print("类属性值:%s" % Person.age)  

在这里插入图片描述
总结如下:

  • 类属性在类创建时就存在于类的内存空间中。
  • 如果类的构造函数中没有初始化对象属性,那么对象在创建时内存空间是没有这个属性的。
  • 实例属性是通过赋值语句来动态创建的。如果没有动态创建,通过对象访问和类同名的属性时,会现在对象内存空间中查找是否有该属性,没有就去类内存空间中查找。
  • 如果已经动态创建了实例属性,那么Python使用对象访问和类同名的属性时,是一定先访问对象内存空间中的实例属性的。

3.4 私有成员与公有成员

类的成员,是类的数据成员和类的方法的统称。为了控制对类的成员的访问权限,类的成员分:公有、保护 、私有三种类型。

  • 公有成员:任何时候都可以访问的成员即为公有成员,在定义类的公有成员时没有什么特殊的要求;
  • 保护成员:名称以一条下划线“_”开头的成员为保护成员。例如:_x、_fun()。保护成员一般都是可以访问的,只是不能用“from module import * ”语句把其它模块定义的保护成员导入到当前模块;
  • 私有成员:名称以两条下划线“__”开头的成员为私有成员。例如:__x、__fun()。私有成员一般不能在类的定义语句外访问。不过,通过“类名._类名私有成员名”(类名和私有成员名之间不要有没有任何的分隔符)或“对象名._类名私有成员名”这样的特殊方式仍然可以访问。

例1:

class Mycls01:
	x = 1 # 公有成员
	_y = 2 # 保护成员
	__z = 3 # 私有成员

# 通过类名访问:
print(Mycls01.x) # 公有成员能访问:1
print(Mycls01._y) # 保护成员也能访问:2
print(Mycls01._Mycls01__z) # 私有成员通过“类名._类名私有成员名”的方式可以访问:3
print(Mycls01.__z) # 私有成员不能直接用类名访问:AttributeError: type object 'Mycls01' has no attribute '__z'

# 通过对象名访问:
obj01 = Mycls01()
print(obj01.x) # 公有成员能访问:1
print(obj01._y) # 保护成员也能访问:2
print(obj01._Mycls01__z) # 私有成员通过“对象名._类名私有成员名”的方式可以访问:3
print(obj01.__z) # 私有成员不能直接用对象名访问:AttributeError: 'Mycls01' object has no attribute '__z'

例2:

class Mycls02:
	def __init__(self):
		self.a = 7 # 公有成员
		self._b = 8 # 保护成员
		self.__c = 9 # 私有成员

obj02 = Mycls02()
print(obj02.a) # 公有成员能访问:7
print(obj02._b) # 保护成员也能访问:8
print(obj02._Mycls02__c) # 私有成员通过“对象名._类名私有成员名”的方式可以访问:9
print(obj02.__c) # 私有成员不能直接用对象名访问:AttributeError: 'Mycls02' object has no attribute '__c'

3.5 静态方法

静态方法的定义如下:

  1. 通过装饰器@staticmethod定义静态方法;
  2. @staticmethod必须写在方法上;
  3. 在静态方法中访问实例属性和实例方法会导致错误;
  4. 调用格式:“类名.静态方法名(参数列表)”。

例1::

class Person:
    # 类属性
    school = "SWPU"
    tuition = 100000
    count = 0
    
    # 实例属性
    def __init__(self,name,age):
        self.name = name
        self.age = age
        Person.count = Person.count+1
 
    # 静态实例
    @staticmethod
    def addNum(a,b):
      print("{0}+{1}={2}".format(a,b,a+b))
      return a+b
 
    # 实例方法
    def get_score(self):
        print("姓名:{0};年龄:{1}".format(self.name,self.age))
 
stu1 = Person("Zhang", 22)
stu1.get_score()
Person.addNum(1,2)

4 继承

继承用于类的创建上,新创建的叫子类,而被继承的叫做父类。子类可以使用父类属性,继承是描述类与类之间的关系。
为什么要用继承呢?因为继承可以减少代码的冗余以及提高代码的重用性。我们在工作中,用到继承的地方很多。
Python里继承总共有单继承、多继承和多层继承。

4.1 单继承

单继承指的是子类只继承一个父类。
例1:

class A():
    def __init__(self):
        self.a = 'a'
 
    def test_a(self):
        print("aaaa")
    
 
class B(A):
    def __init__(self):
        self.b = 'b'
 
    def test_b(self):
        self.test_a()	#调用A类的方法test_a
        print("bbbb")
 
 
obj = B()
obj.test_b()

4.2 多继承

多继承指的是子类继承了多个父类。

class A():
    def __init__(self):
        self.a = 'a'
 
    def test_a(self):
        print("aaaa")
    
 
class B():
    def __init__(self):
        self.b = 'b'
 
    def test_b(self):
        print("bbbb")
 
 
class C(A, B):
    def __init__(self):
        self.c = 'c'
 
    def test_c(self):
        self.test_a()
        self.test_b()

例子中,C类就分别继承了A类和B类的方法。 多层继承就是指子类继承的父类也有继承别的类,这里就不举例了。

4.3 子类重写父类方法

在某些场景下,子类继承了父类的属性和方法,但子类有同名的方法,这时候就需要重写子类的方法了。

class A():
    def __init__(self):
        self.a = 'a'
 
    def test(self):
        print("aaaa")
    
 
class B(A):
    def __init__(self):
        self.b = 'b'
        super().__init__()
 
    def test(self):
        print("bbbb")

例子中B类继承A类的属性和test()方法,但B也有test方法,那么只需要在B类中重新定义个test()方法即可。

4.4 继承中的注意事项

  • 子类如果重写了__init__方法,子类就不会自动继承父类__init__中的属性。如果要继承父类的属性,需要用到super方法,我们在B类的__init__方法中加上:
super(子类,self).__init__(参数0,参数1...)
父类名称.__init__(self,参数0,参数1...)

若继承父类的所有属性就直接用:

super().__init__()

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

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

相关文章

基于springboot家具商城系统

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SpringBoot 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 开发软件:IDEA / Eclipse 是否Maven项目:是 前言 基于springboot家具商…

js数组排序的两种方法

1. 冒泡排序 原理&#xff1a;一次比较两个相邻的数&#xff0c;如果不符合规则互换位置&#xff0c;一次比较就能够将最大或最小的值放在数组最后一位继续对除【最后一位】之外的所有元素重复上述过程。 let arr [22,1,43,12,75,32]; for(let i 0; i < arr.length - 1;…

MySQL一条查询语句是怎么执行的?MySQL 的架构是什么样子?

先谈谈MySQL的架构&#xff0c;这样自然就搞清楚一条语句是怎么执行的了 首先&#xff0c;MySQL分为客户端&#xff0c;服务端&#xff0c;存储引擎 客户端&#xff1a; ● Java程序啊&#xff0c;可视化连接工具 Navicat啊等等&#xff0c;就是客户端&#xff1b; 服务端&…

Vivado 下 IP核 之ROM 读写

目录 Vivado 下 IP核 之ROM 读写 1、实验简介 2、ROM IP 核简介 3、ROM IP 核配置 3.1、创建 ROM 初始化文件 3.2、单端口 ROM 的配置 3.3、双端口 ROM 的配置 3.4、ROM IP 核的调用 &#xff08;1&#xff09;ROM 顶层模块代码 &#xff08;2&#xff09;ROM IP 核仿…

lua-5.3.6源码安装

参考博客有https://blog.csdn.net/m0_53157173/article/details/124653430和http://blog.chinaunix.net/uid-14824714-id-3125340.html。 https://www.lua.org/download.html下载网址。点击当前网址中的“download”超链接可以下载以前的版本。 cat /etc/redhat-release看一下…

408考研计算机之计算机组成与设计——计算机层次系统概述2

目录 一、 冯诺依曼机基本思想 二、计算机的功能部件 1、输出输入设备 2、存储器 3、运算器 4、控制器​​​​​​​ 三、指令执行过程的描述 一、 冯诺依曼机基本思想 首先&#xff0c;第一个问题&#xff0c;冯诺依曼是谁&#xff1f;小编第一次知道这个名字&#xff…

Qt将十二位整形十进制转换成十六进制,在转为ascii字符,并下发串口。在接受端完整还原这个十二位的十进制数。

可以按照以下步骤进行操作&#xff1a; 将十进制数123456789012转换成十六进制字符串&#xff1a; QString hexString QString("%1").arg(123456789012ull, 0, 16);其中&#xff0c;%1表示替换第1个参数&#xff0c;0表示输出的最小位数为0&#xff0c;16表示输出…

Capturing Omni-Range Context for Omnidirectional Segmentation总结笔记

Capturing Omni-Range Context for Omnidirectional Segmentation&#xff08;捕获全范围上下文进行全方位分割&#xff09; 目录 一、论文出发点 二、论文核心思想 三、论文工作中主要问题 四、方法论 五、实验 六、结论 一、论文出发点 大多数用于分析城市环境的分割…

springboot+swagger项目中,controller引入@NotEmpty等校验注解的问题

springboot项目 springbootswagger项目中&#xff0c;controller层如果使用对基本数据类型使用 NotEmpty Length 等校验注解&#xff0c;controller会获取不到值&#xff0c;加了RequestBody后可以获取到了&#xff0c;但是前端传值content-type必须是text/plain。所以建议con…

考研数据结构--树和二叉树(2)

文章目录 二叉树的遍历前序遍历中序遍历后序遍历层次遍历 不用栈的二叉树中序遍历算法Morris代码分析 二叉树的构造概述如何完成二叉树的构造**回顾****思考**各种遍历序列提供的信息二叉树遍历性质性质1性质2 线索化二叉树引入定义构造 堆堆的定义堆的性质堆的建立堆的元素插入…

GPT1解读:Improving Language Understanding by Generative Pre-Training

自然语言处理NLP是当代人工智能的关键领域&#xff0c;包含文本识别、智能问答等多个方向任务&#xff0c;通过监督学习方式一般需要大量带标签数据&#xff0c;而对某些特定任务&#xff0c;获取带标签数据成本非常高。GPT通过大量的未标记文本数据来学习一个通用预训练&#…

ZiKiT DICOM 存档(PACS)模态服务器 Crack

ZiKiT结合了DICOM存档&#xff08;PACS&#xff09;&#xff0c;模态工作列表服务器和HL7消息代理&#xff0c;它们共享相同的数据库并相互通信。 最新版本 – ZiKiT 2020 ZiKiT 提供动态映射规则和消息结构定义&#xff0c;同时保持合规性并遵守标准。该套件使非程序员能够在…

电动力学:电偶极辐射场

电磁辐射的产生条件 存在时变源&#xff08;时变的电荷源、时变的电流源&#xff0c;或时变的电磁场&#xff09;时变源的频率应足够高&#xff08;辐射系统的尺寸大小和电磁波波长差不多时&#xff0c;才有可能产生明显的辐射效应&#xff09;波源电路必须开放&#xff08;源电…

Android 如何获取有效的DeviceId

目录 前言官方唯一标识符建议使用广告 ID使用实例 ID 和 GUID不要使用 MAC 地址标识符特性常见用例和适用的标识符 解决方案DeviceIdANDROID_IDMac地址UUID补充 总结 前言 从 Android 10 开始&#xff0c;应用必须具有 READ_PRIVILEGED_PHONE_STATE 特许权限才能访问设备的不可…

新手建站:腾讯云轻量服务器安装宝塔镜像和使用方法

腾讯云轻量应用服务器宝塔面板怎么用&#xff1f;轻量应用服务器如何安装宝塔面板&#xff1f;在镜像中选择宝塔Linux面板腾讯云专享版&#xff0c;在轻量服务器防火墙中开启8888端口号&#xff0c;然后远程连接到轻量服务器执行宝塔面板账号密码查询命令&#xff0c;最后登录和…

Java内存模型介绍

Java作为一种面向对象的&#xff0c;跨平台语言&#xff0c;其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似&#xff0c;很多人会傻傻分不清楚。比如本文要讨论的JVM内存结构、Java内存模型和Java对象模型&#xff0c;这就是三个截然不同的概念&…

系列四、vue3 初始化项目(图形化界面方式)

一、启动UI界面 vue ui 二、创建项目 2.1、在此创建项目 2.2、创建新项目-详情配置 2.3、创建新项目-预设 2.4、创建新项目-功能 2.5、创建新项目-配置 2.6、运行项目 任务》serve》运行》启动app 2.7、首页 三、安装element-plus 3.1、步骤 ①、运行 vue ui 命令&#…

【C++初阶】想要编译器为你干活吗?来试试模板吧(模板初阶)

一.泛型编程 引入 我们之前都写过交换函数Swap&#xff0c;例如这样的&#xff1a; //交换两个整型 void Swap(int*x1, int *x2) {int tmp *x1;*x1 *x2;*x2 tmp;} 如果要交换其它的类型该怎么办呢&#xff1f; 那只能当个CV工程师了&#xff0c;然后再修修改改&#xff0c;…

java枚举enum

目录 一、概念二、声明枚举三、枚举类四、为枚举添加方法五、EnumMap 与 EnumSet 一、概念 枚举是一个被命名的整型常数的集合&#xff0c;用于声明一组带标识符的常数。枚举在曰常生活中很常见&#xff0c;例如一个人的性别只能是“男”或者“女”&#xff0c;一周的星期只能…

CAN总线通讯协议学习

s目录 CAN&#xff08;controller Area Network) 控制器局域网 CAN通讯 CAN总线的数据帧 解析 CAN&#xff08;controller Area Network) 控制器局域网 CAN总线应用最多的是汽车领域,这里的控制器在汽车领域的专业术语是ECU.(electronic control unit)电子控制单元。可以看成…