Python程序设计-AI辅助编程-课件 第9章 面向对象编程_第1页
Python程序设计-AI辅助编程-课件 第9章 面向对象编程_第2页
Python程序设计-AI辅助编程-课件 第9章 面向对象编程_第3页
Python程序设计-AI辅助编程-课件 第9章 面向对象编程_第4页
Python程序设计-AI辅助编程-课件 第9章 面向对象编程_第5页
已阅读5页,还剩50页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第九章

面向对象编程Python程序设计本章要点面向对象编程核心思想面向对象编程基础类与对象DeepSeek的使用学习目标了解面向对象编程的基本概念及类与对象的关系;理解封装、继承、多态等核心思想及其在程序设计中的作用;掌握类的定义、属性与方法的编写,以及方法重写、多重继承和组合的实现;熟悉面向对象程序的构建方式,培养抽象思维能力、代码复用意识和工程化开发素养。1面向对象编程基础面向对象编程基础面向对象编程(Object-OrientedProgramming,OOP)是一种编程范式,其基础在于“对象”的概念,用于组织代码与数据。该范式的核心在于将数据及其操作方法(函数)封装于对象内部,并通过对象间的相互作用实现程序的复杂逻辑。编程活动涉及创建具有特定功能的对象,并确定在何时调用这些对象以实现既定功能。例如:应用面向对象编程理念以完成洗碗任务时,可以构建一个具备冲洗、添加洗涤剂、再次冲洗及排水功能的洗碗机对象。用户在进行餐具清洁时,仅需操作洗碗机,该设备将自动执行整个洗碗过程。面向对象编程基础面向对象编程具备三大基本特征,分别为封装、继承与多态。封装作为面向对象编程的核心,它将对象的属性(即数据)与行为(即方法)予以封装,而类则是产生对象的载体。经过封装后,类会对自身细节加以隐藏,其他对象虽可对其进行调用,但并不知晓其内部结构。继承指的是在面向对象编程里,类能衍生自身的子类,子类具备父类的属性与行为,同时还可拓展自身的属性与行为。多态是自然界普遍存在的一种现象,例如鸟类虽然都有“鸣叫”行为,但具体叫声各不相同。程序设计中,多态指同一操作对于不同类的实例,可以产生不同的执行结果。面向对象编程基础子类的实例对象属于父类的对象,然而父类的实例对象未必是子类的实例对象。例如:动物可视为一个类,小羊肖恩便是动物类的实例对象。人类作为动物类的子类,张三是人类的实例对象,同时也是动物类的实例对象,但不能认定小羊肖恩是人类的实例对象。动物类具有一些属性,如性别、年龄等,还具有一些行为,如进食。人类继承了动物类的属性与行为,同时也拓展了自身的属性与行为,如姓名属性与读书行为。

2类与对象对象Python中任何一个具有属性和方法的事物都可以称作对象,对于一类对象的抽象就称为类(Class)。对象具有唯一性,每一个对象都是独立的个体,都有自己的特点和行为,对象与对象之间可以有联系也可以有相互作用。类的定义Python中通过class关键字来定义类:classClassName:"""类的文档注释信息"""pass#类的主体,此处省略,pass只起占位作用类的命名采用大驼峰的形式,即多个单词,每个单词首字母大写组合而成。类的定义在类中定义的函数通常称为方法(method),虽然本质上是一种特殊的函数,但二者并不完全等同。简单来说,函数是独立存在的可执行代码块,而方法是属于某个类或对象的函数,与其实例或类紧密关联,通常用于操作对象的数据或实现对象的行为。每个方法至少需要一个参数,当通过实例调用方法时,实例会自动作为第一个参数传递,也因此Python使用self作为参数名,这只是一个约定,用户也可以自行命名。类的定义类的定义里,一般有一个特殊方法:__init__()方法,一旦创建某个类的实例,该方法便会自动被调用;此方法的关键功能在于初始化实例的属性。在类的定义中,可以定义多个不同的构造方法__init__()。__init__()方法的第一个参数是self,在创建实例时无需传递该参数。__init__()中self后面的参数可以在创建实例时传进来,这样可以初始化该实例的一些属性。定义好类之后并不会直接创建实例,可以把类理解成一个模板,通过这个模板可创建实例。创建类实例的语法同变量赋值比较像,通过变量名、赋值符号、类名加括号实现。类的定义classCar:"""这里将定义一个汽车类"""carSeries=""

def__init__(self,series):self.carSeries=seriesmyCar=Car('红旗H9')#创建汽车类的实例myCar,并传入参数print(myCar.carSeries)#输出红旗H9属性用print()语句可以查看宿主(实例对象)的属性。myCar.type="SUV"#给实例myCar添加type属性,属性值是"SUV"myCar.type="sportscar"#修改myCar的type属性的值属性与变量的区别在于属性有其归属的宿主。每个对象都有属于自己的属性,这些属性能够被添加、查看、修改以及删除。添加和修改操作可直接通过赋值语句实现,当该属性不存在时即为添加,存在时则为修改。print(myCar.type)#myCar是实例对象,输出:sportscar属性用del关键字可以删除属性。print(myCar.__dict__)#输出{'carSeries':'红旗H9','type':'sportscar'}可以通过__dict__属性查看对象的所有属性。delmyCar.type #删除myCar的type属性print(myCar.type) #会报错并且提示myCar没有type属性属性Car.max_fuel=70#新增max_fuel属性Car.max_fuel=50#修改max_fuel属性的值print(Car.max_fuel)#输出Car的max_fuel属性的值print(Car.__dict__)#输出Car的所有属性,发现新增了'max_fuel':50类的属性同样也有增查改删,语法和对象属性基本一样。属性classStudent:"""定义Student类,有一个年龄属性"""age=18#类属性age的值是18zhangsan=Student()#实例化print(zhangsan.age)#age属性值,输出18print(zhangsan.__dict__)#实例没有自己的属性,输出{}zhangsan.age=19#更改zhangsan实例age属性的值print(zhangsan.__dict__)#实例的增加了一个属性输出{'age':19}print(Student.__dict__)#类的属性未发生变化{...,'age':18,...}'''输出{'__module__':'__main__','__doc__':'定义Student类,有一个年龄属性','age':18,'__dict__':<attribute'__dict__'of'Student'objects>,'__weakref__':<attribute'__weakref__'of'Student'objects>}'''当这个类实例化之后,实例对象也具有这些属性。这个时候如果更改类的属性同时会更改实例对象的属性,但是更改实例对象的属性不会更改类的属性。属性current_year=2022#定义全局变量,当前年份classStudent:def__init__(self,born_year):#定义__init__()方法self.born_year=born_year#出生年份@property#将方法转化成属性defage(self):#计算年龄的实例方法returncurrent_year-self.born_year#返回年龄zhangsan=Student(2002)#实例化Student类print(zhangsan.age)#输出20可以通过@property语句把方法转化成属性,这样就可以让类的属性根据其他的值变化而变化。属性Python通过属性名来决定属性的访问权限。内置的特殊属性:属性名之前和之后都有两个下划线。公有属性:属性名之前没有下划线,公有属性可以被类和子类内部访问,也可以被类外部访问,甚至这个属性可以通过import形式导入实现跨模块访问。#模块名Module1,包名OOPclassStudent:"""定义Student类,公有属性age值为10"""

age=10defshow(self):"""输出公有属性age的值"""print("类内部调用属性age的值:",Student.age)#输出类内部调用属性age的值:10if__name__=='__main__':zhangsan=Student()#实例化zhangsan.show()#调用实例的show()方法print("实例对象属性age值:",zhangsan.age)#输出实例对象属性age值:10print("类对象属性age值:",Student.age)#输出类对象属性age值:10属性importOOP.Module1print("学生年龄为:",OOP.Module1.Student.age)#跨模块调用,输出:学生年龄为:10另一个模块通过import形式导入,实现跨模块访问。fromOOP.Module1import*print("学生年龄为:",Student.age)#跨模块调用,输出:学生年龄为:10也可以用“*”导入模块中的全部类。属性Python通过属性名来决定属性的访问权限。3.私有属性:属性名之前有两个下划线,私有属性的访问权限更局限,只能类内部访问,继承他的子类没有权限访问,同时也不能通过“类名.私有属性”访问或者“实例名.私有属性”访问。classStudent:"""定义Student类,私有属性__age值为10"""

__age=10defshow(self):"""类内部可以访问私有属性"""print("类内部调用:",Student.__age)if__name__=='__main__':zhangsan=Student()zhangsan.show()#print("实例对象调用:",zhangsan.__age)#取消注释将触发异常#异常:AttributeError:'Student'objecthasnoattribute'__age'#print("类对象调用:",Student.__age)#取消注释将触发异常#异常:AttributeError:typeobject'Student'hasnoattribute'__age'方法deffunction(parameters):passclassClassName:defmethod(self,parameters):passif__name__=='__main__': function(parameter)#调用函数 ClassName.method(parameters)#调用方法方法和函数相似,都是将一系列的行为封装起来。两者都可以被调用,执行一系列操作,但是调用方式不同。方法Python中把方法划分成三种类型:实例方法,类方法和静态方法。三种方法的区别是方法的第一个参数接受的类型不同:实例方法第一个参数是self类方法第一个参数是cls静态方法不需要第一个参数。很多IDE(IntegratedDevelopmentEnvironment,集成开发环境)会自动添加self和cls参数。创建实例方法的语法:classClassName:definstance_method(self):"""创建一个实例方法"""pass方法classStudent:defstudy(self,subject):"""创建一个实例方法"""print("人生苦短,我学"+subject)#输出人生苦短,我学Pythonif__name__=='__main__':zhangsan=Student()zhangsan.study("Python")#调用时略过self,只为参数subject传值若需要更多参数,直接在self参数后面添加。调用实例方法的时候,Python会自动把调用实例方法的对象传给self参数,所以我们只要给出self后面参数的值就可以了。实例对象调用方法时,self参数就是实例对象本身。方法classClassName:@classmethod#将函数转化成类方法defclass_method(cls):"""创建一个类方法"""passif__name__=='__main__':ClassName.class_method()#调用类方法创建类方法和调用类方法的语法。方法classStudent:@classmethoddefstudy(cls,subject):"""创建一个类方法,添加一个subject参数"""print("人生苦短,我学"+subject)#输出:人生苦短,我学Pythonif__name__=='__main__':Student.study("Python")#通过类调用类方法zhangsan=Student()zhangsan.study("Python")#通过实例调用类方法类方法的第一个参数一定是cls,添加参数和实例方法一样,类方法也可以通过实例来调用。方法classClassName:@staticmethod#将函数转化成静态方法defstatic_method():print("静态方法")if__name__=='__main__':ClassName.static_method()instance=ClassName()instance.static_method()静态方法不传递任何实例和类,可以避免经常实例化占用资源。方法classClassName:"""定义ClassName类,拥有一个公有方法和一个私有方法"""defpublic_func(self):"""外部可以直接调用的公有方法"""print("公有方法")def__private_func(self):"""只有内部可以直接调用的私有方法"""print("私有方法")defshow(self):print("类内部调用:")self.public_func()self.__private_func()instance1=ClassName()instance1.public_func()#instance1.__private_func()#类的外部不能访问,运行这行会报错instance1.show()方法的访问权限划分和属性是一样的,都是通过下划线来区分。没有下划线的时候代表外部可以直接调用,两个下划线是私有方法只能类内部调用。方法ls=[5,4,1,3,2]ls.sort() #sort()是一个实例方法,解释器自动将ls对象传给sort()在实例方法、类方法以及静态方法里,使用频率最高的是实例方法。日常中,我们对列表所做的诸多操作,像sort()、reverse()、remove()、pop()等,都属于实例方法。方法a=10print(a.from_bytes([0,0,1,0],'big'))#输出256print(int.from_bytes([0,0,1,0],'big'))#输出256print(a)#a的值没有任何变化,输出10类方法在调用时,其首个参数为类,即实例所隶属的类。类方法的应用场景相对较少,比如:使用from_bytes()来返回由特定字节数组表示的整数。静态方法不能访问类/实例属性,只是封装在类中的工具函数,常用于与类相关但独立的辅助功能;因此静态方法通常在用户自定义类中使用,Python标准库中内置静态方法极少,str.maketrans()

是最典型且常用的。3面向对象编程核心思想封装封装是面向对象编程的核心思想之一。通过封装,可以隐藏类的内部实现细节,仅暴露必要的接口供外部调用,从而提高代码的安全性和可维护性。在封装的过程中,通常会使用私有属性(通常以双下划线开头,如__attribute)来限制外部直接访问。外部代码如果需要访问或修改这些私有属性,必须通过类提供的公共方法(如getter和setter方法)来实现。这种方式确保了数据的访问和修改都在类的控制之下,可以有效地防止数据被意外修改或不合法的数据访问。封装classBankAccount:

def__init__(self,balance):

self.__balance=balance

#私有属性(封装)

defdeposit(self,amount):

#公开接口

ifamount>0:

self.__balance+=amount

defget_balance(self):

#公开接口

returnself.__balance封装还有助于实现代码的重用。通过将数据和操作数据的方法捆绑在一起,可以创建一个具有特定功能的模块,然后在需要时实例化这个类来使用其功能,而无需关心其内部实现细节。这大大提高了代码的复用性和可维护性。继承在程序设计中,继承代表一个类拥有另外一个类的(部分)资源。本书把被继承的类称为父类,继承的类称为子类。继承相当于子类拥有父类的部分属性和方法,但注意只是子类能使用到父类的资源,而不是资源的复制。继承基本语法格式如下:classFather:"""定义一个父类(基类)"""passclassSon(Father):"""子类,Father为当前类的父类,多个父类时用逗号分隔"""pass继承classFather:"""定义一个父类(基类)"""

__age=50#私有属性gender="male"defget_age(self):print(self.__age)#类内部可以调用私有属性classSon(Father):"""子类,继承基类Father中非私有的属性和方法"""defget_gender(self):print(self.gender)#可以调用,输出maledefget_father_age(self):print(self.__age)#无法继承私有属性,调用不到子类继承父类只能继承非私有的属性和方法继承if__name__=='__main__':zhangsan=Father()zhangsan.get_age()#输出50zhangsi=Son()#调用子类zhangsi.get_gender()#输出malezhangsi.get_father_age()#异常AttributeError:'Son'objecthasnoattribute'_Son__age'子类继承父类只能继承非私有的属性和方法继承classFather:"""定义一个父类(基类)"""moneyPerYear=100000year=0def__init__(self,year):self.year=year

def__my_money(self,year):"""私有方法"""return100000*yeardefget_money(self):print(self.__my_money(self.year))方法的继承与属性相同,子类也只能继承父类的非私有方法继承classSon(Father):"""子类,继承基类Father中非私有的属性和方法"""defget_father_money(self):print(self.__my_money(self.year))#__my_money()是私有方法if__name__=='__main__':laoli=Father(10)laoli.get_money()#输出1000000xiaoli=Son(10)xiaoli.get_father_money()#异常AttributeError:'Son'objecthasnoattribute'_Son__my_money'方法的继承与属性相同,子类也只能继承父类的非私有方法方法重写classFather():"""定义一个父类(基类)"""salary=30000defannual_salary(self,salary):returnsalary*12classSon(Father):"""子类,继承基类Father中非私有的属性和方法"""salary=5000#属性覆盖/属性遮蔽defannual_salary(self,salary):#方法重写returnsalary*10若父类方法的功能无法满足需求,子类可重写父类的方法。解释器会优先查找子类中的属性与方法,若子类未重写,才使用父类的属性与方法。方法重写if__name__=='__main__':laoli=Father()xiaoli=Son()print(laoli.salary)#返回基类中的值,输出30000print(xiaoli.salary)#优先返回子类son里的salary的值,输出5000print(laoli.annual_salary(laoli.salary))#基类中的方法,输出360000print(xiaoli.annual_salary(xiaoli.salary))#子类里的方法,输出50000若父类方法的功能无法满足需求,子类可重写父类的方法。解释器会优先查找子类中的属性与方法,若子类未重写,才使用父类的属性与方法。多重继承多重继承允许一个子类同时继承多个父类,通过多重继承,子类可以复用多个父类的代码,从而增加代码的复用性和灵活性。下面定义的Bird类同时继承Animal(基础属性)和Flyable(飞行能力),无需在Bird中重复实现这两类功能。classAnimal:#父类1def__init__(self,name):=namedefeat(self):print(f"{}iseating")classFlyable:#父类2deffly(self):print(f"{}isflying")classBird(Animal,Flyable):#子类defsing(self):print(f"{}issinging")bird=Bird("Sparrow")bird.eat()#继承自Animalbird.fly()#继承自Flyablebird.sing()#自身方法多重继承多重继承是一把"双刃剑":合理使用可以极大提升代码复用和灵活性(如混入类模式),但滥用会导致代码复杂度飙升、维护困难。如在不同父类包含同名方法或属性时,就会产生命名冲突。classA:#父类defaction(self):print("ActionfromA")classB:#父类defaction(self):print("ActionfromB")#父类顺序为A,BclassC(A,B):#子类passc=C()c.action()#输出:"ActionfromA"(A在B前面,优先被调用)#父类顺序为B,AclassD(B,A):#子类passd=D()d.action()#输出:"ActionfromB"(B现在在前面)多重继承这种冲突需要通过方法解析顺序(MRO机制:Child→Left→Right→Base)或显式调用父类方法来解决。classA:#父类defaction(self):print("ActionfromA")classB:#父类defaction(self):print("ActionfromB")classC(A,B):#子类defaction(self):A.action(self)#显式调用A的funcclassD(A,B):#子类defaction(self):B.action(self)#显式调用B的funcc=C()c.action()d=D()d.action()多重继承MRO(MethodResolutionOrder)是Python在多重继承中,查找属性和方法顺序的规则。当调用一个方法或访问一个属性时,Python按照MRO定义的顺序依次查找,找到第一个匹配的就停止。MRO算法:使用C3线性化算法,保证:

每个类只出现一次

子类优先于父类,左父类优先于右父类(从左到右)

单调性(保持继承顺序的一致性)C3算法核心公式:MRO(C)=[C]+merge(MRO(P₁),MRO(P₂),...,[P₁,P₂,...])C是当前类P₁,P₂,...是C的直接父类(按声明顺序)merge()是合并函数merge(L₁,L₂,...,Lₙ)的算法:步骤1:检查所有非空列表的头部

取第一个列表L₁

的头部H步骤2:检查H是否在其他列表L₂...Lₙ的尾部出现

(尾部=除头部外的所有元素)步骤3:判断-如果H不在任何尾部出现:

✅H是好的

将H加入结果

从所有列表中移除H

【返回步骤1,重新开始】⬅️

关键!

-如果H在某个尾部出现:

❌H不能选

尝试下一个列表的头部

如果所有头部都不能选,报错(MRO冲突)步骤4:重复直到所有列表为空merge(L₁,L₂,...,Lₙ)流程图与举例:classO:passclassA(O):passclassB(O):passclassC(A,B):passMRO(O)=[O,object]MRO(A)=[A,O,object]MRO(B)=[B,O,object]MRO(C)=[C]+merge(MRO(A),MRO(B),[A,B])=[C]+merge([A,O,object],[B,O,object],[A,B])merge过程:──────────────────────────────迭代

列表1列表2列表3操作──────────────────────────────1[A,O,object][B,O,object][A,B]取AA在列表2尾部[O,object]吗?否A在列表3尾部[B]吗?否

选A

结果:[C,A]

移除A:[O,object],[B,O,object],[B]2[O,object][B,O,object][B]取OO在列表2尾部[O,object]吗?是❌尝试B(列表2头部)B在列表1尾部[object]吗?否B在列表3尾部[]吗?否✅选B结果:[C,A,B]移除B:[O,object],[O,object],[]3[O,object][O,object][]取OO在其他尾部吗?否✅选O结果:[C,A,B,O]移除O:[object],[object],[]4[object][object][]取object✅选object结果:[C,A,B,O,object]所有列表为空,完成!最终MRO(C)=[C,A,B,O,object]─────────────────────────────迭代列表1列表2列表3操作─────────────────────────────组合组合允许对象拥有其他对象作为自身的属性,并借助这些内容对象的公共接口实现互动。这种形式区别于多重继承,多重继承通过继承多个父类的属性与方法来增强类的功能。而组合则是把现有的类作为新类的成员属性,利用现有类为新类提供所需功能。使用组合能够规避多重继承引发的复杂性及潜在冲突,同时提升代码的可读性与可维护性。组合组合表示“拥有”关系,即一个对象(称为容器对象)包含另一个对象(称为被包含对象)。被包含对象作为容器对象的一个属性存在。#电脑由CPU、内存等硬件组成,体现"整体-部分"关系:classCPU:

defcalculate(self):

print("CPU正在计算")classMemory:

defstore(self,data):

print(f"内存存储数据:{data}")classComputer:

def__init__(self):

self.cpu=CPU()

#组合CPU对象

self.memory=Memory()#组合Memory对象

defrun(self,task):

print(f"执行任务:{task}")

self.memory.store(f"任务数据:{task}")#调用组合Memory对象的方法

self.cpu.calculate()#调用组合CPU对象的方法#使用my_pc=Computer()my_pc.run("图像处理")组合组合允许在运行时动态地添加、删除或替换被包含对象,从而提供更大的灵活性。#电脑由CPU、内存等硬件组成,体现"整体-部分"关系,此例动态升级CPUclassCPU:def__init__(self,model,cores):self.model=modelself.cores=coresdefprocess(self,task):returnf"CPU{self.model}({self.cores}核)正在处理:{task}"classMemory:def__init__(self,capacity,type_):self.capacity=capacityself.type=type_defstore(self,data):returnf"内存{self.capacity}GB{self.type}存储数据:{data}"classComputer:def__init__(self,cpu,memory):#组合硬件组件self.cpu=cpuself.memory=memory

defupgrade_cpu(self,new_cpu):"""动态更换CPU"""old_model=self.cpu.modelself.cpu=new_cpureturnf"已将CPU从{old_model}升级为{new_cpu.model}"defrun_program(self,program):"""运行程序,调用各硬件组件协同工作"""steps=[]steps.append(self.memory.store(f"{program}的运行数据"))steps.append(cess(f"{program}的计算任务"))return"\n".jo

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论