Python程序设计基础(微课版 在线练习与考试软件版)课件 第9章 面向对象程序设计_第1页
Python程序设计基础(微课版 在线练习与考试软件版)课件 第9章 面向对象程序设计_第2页
Python程序设计基础(微课版 在线练习与考试软件版)课件 第9章 面向对象程序设计_第3页
Python程序设计基础(微课版 在线练习与考试软件版)课件 第9章 面向对象程序设计_第4页
Python程序设计基础(微课版 在线练习与考试软件版)课件 第9章 面向对象程序设计_第5页
已阅读5页,还剩47页未读 继续免费阅读

下载本文档

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

文档简介

第9章面向对象程序设计1本章学习目标掌握定义类的语法掌握创建对象的语法理解数据成员与成员方法的区别理解私有成员与公有成员的区别理解属性的工作原理了解继承的基本概念了解特殊方法的概念与工作原理2第9章面向对象程序设计在面向对象程序设计(ObjectOrientedProgramming)中,把数据以及对数据的操作封装在一起,组成一个整体(对象),不同对象之间通过消息机制来通信或者同步。对于相同类型的对象进行分类、抽象后,得出共同的特征而形成了类。创建类时用变量形式表示对象特征的成员称为数据成员,用函数形式表示对象行为的成员称为成员方法,数据成员和成员方法统称为类的成员。以设计好的类为基类,可以继承得到派生类,大幅度缩短开发周期,并且可以实现设计复用。在派生类中还可以对基类继承而来的某些行为进行重新实现,从而使得基类的某个同名方法在不同派生类中的行为有可能会不同,体现出一定的多态性。封装、继承、多态是面向对象程序设计的三个要素。39.1类的定义与使用Python使用class关键字来定义类,class关键字之后是一个空格,接下来是类的名字,如果派生自其它基类的话则需要把所有基类放到一对圆括号中并使用逗号分隔,然后是一个冒号,最后换行并定义类的内部实现。类名的首字母一般要大写,当然也可以按照自己的习惯定义类名,但是一般推荐参考惯例来命名,并在整个系统的设计和实现中保持风格一致。classCar(object):#定义一个类,派生自object类defshowInfor(self):#定义成员方法print('Thisisacar')49.1类的定义与使用定义了类之后,就可以用来实例化对象,并通过“对象名.成员”的方式来访问其中的数据成员或成员方法。car=Car()#实例化对象car.showInfor()#调用对象的成员方法59.2数据成员与成员方法创建类时用变量形式表示对象特征的成员称为数据成员(attribute),用函数形式表示对象行为的成员称为成员方法(method),数据成员和成员方法统称为类的成员。69.2.1私有成员与公有成员从形式上看,在定义类的成员时,如果成员名以两个下划线开头但是不以两个下划线结束则表示是私有成员。私有成员在类的外部不能直接访问,一般是在类的内部进行访问和操作,或者在类的外部通过调用对象的公有成员方法来访问。公有成员是可以公开使用的,既可以在类的内部进行访问,也可以在外部程序中使用。Python并没有对私有成员提供严格的访问保护机制,通过一种特殊方式“对象名._类名__xxx”也可以在外部程序中访问私有成员,但这会破坏类的封装性,不建议这样做。79.2.1私有成员与公有成员>>>classTest:def__init__(self,value=0): #构造方法,创建对象时自动调用self.__value=value #私有数据成员defset_value(self,value): #公有成员方法,需要显式调用self.__value=value #在类内部可以直接访问私有成员defshow(self): #公有成员方法print(self.__value)>>>t=Test()>>>t.show() #在类外部直接访问公有成员0>>>t._Test__value #在外部使用特殊形式访问私有数据成员089.2.1私有成员与公有成员在Python中,以下划线开头的变量名和方法名有特殊的含义,尤其是在类的定义中。_xxx:受保护成员;__xxx__:系统定义的特殊成员;__xxx:私有成员,只有类对象自己能访问,子类对象不能直接访问到这个成员,但在类外部可以通过“对象名._类名__xxx”这样的特殊方式来访问。注意:Python中不存在严格意义上的私有成员。99.2.2数据成员数据成员用来描述类或对象的某些特征或属性,可以分为属于对象的数据成员和属于类的数据成员。属于对象的数据成员一般在构造方法__init__()中定义,当然也可以在其他成员方法中定义(不建议这样做),在定义时和在实例方法中访问数据成员时以self作为前缀,同一个类的不同对象(实例)的数据成员之间互不影响;属于类的数据成员是该类所有对象共享的,不属于任何一个对象,在定义类时这类数据成员一般不在任何一个成员方法的定义中。109.2.2数据成员利用类数据成员的共享性,可以实时获得该类的对象数量,并且可以控制该类可以创建的对象最大数量。>>>classSingleInstance:num=0def__init__(self):ifSingleInstance.num>0:raiseException('只能创建一个对象')SingleInstance.num+=1

>>>t1=SingleInstance()>>>t2=SingleInstance()Traceback(mostrecentcalllast):File"<pyshell#11>",line1,in<module>t2=SingleInstance()File"<pyshell#9>",line5,in__init__raiseException('只能创建一个对象')Exception:只能创建一个对象119.2.3成员方法Python类的成员方法大致可以分为公有方法、私有方法、静态方法、类方法和抽象方法。公有方法和私有方法主要指属于对象的实例方法,其中私有方法的名字以两个下画线为前缀,公有方法的名字不以下画线为前缀。所有实例方法的第一个参数表示当前对象,一般使用self作为参数名。在实例方法中访问实例成员时需要以self为前缀,不以self作为前缀的都按方法内的局部变量处理。在程序中通过对象调用方法时会把当前对象隐式绑定到self参数,不需要为self显式传递实参。129.2.3成员方法静态方法和类方法可以通过类名和对象名调用,但在这两种方法中不能访问属于对象的成员,只能访问属于类的成员。类方法一般以cls作为第一个参数表示该类自身,调用时自动绑定当前类,不需要为cls参数传递实参。静态方法可以不接收任何参数。139.2.3成员方法>>>classRoot:__total=0def__init__(self,v):#构造方法self.__value=vRoot.__total+=1defshow(self):#普通实例方法print('self.__value:',self.__value)print('Root.__total:',Root.__total)@classmethod#修饰器,声明类方法defclassShowTotal(cls):#类方法print(cls.__total)@staticmethod#修饰器,声明静态方法defstaticShowTotal():#静态方法print(Root.__total)149.2.3成员方法>>>r=Root(3)>>>r.classShowTotal()#通过对象调用类方法1>>>r.staticShowTotal()#通过对象调用静态方法1>>>r.show()self.__value:3Root.__total:1>>>rr=Root(5)>>>Root.classShowTotal()#通过类名调用类方法2>>>Root.staticShowTotal()#通过类名调用静态方法2159.2.3成员方法>>>Root.show()#试图通过类名直接调用实例方法,失败TypeError:unboundmethodshow()mustbecalledwithRootinstanceasfirstargument(gotnothinginstead)>>>Root.show(r)#但是可以通过这种方法调用方法并访问实例成员self.__value:3Root.__total:2>>>Root.show(rr)#通过类名调用实例方法时为self参数显式传递对象名self.__value:5Root.__total:2169.2.3成员方法抽象方法只能在抽象类中定义,抽象类不能实例化,试图这样做时会报错并提示“TypeError:Can'tinstantiateabstractclassAbstractBasewithabstractmethod...”,必须创建抽象类的派生类并实现全部抽象方法之后才能对派生类进行实例化。179.2.3成员方法importabcclassAbstractBase(abc.ABC): #创建抽象类def__init__(self,v):self.value=vdefmodify(self,v):self.value=v@abc.abstractmethoddefshow(self): #定义抽象方法,可以没有具体实现passclassChild(AbstractBase): #继承抽象类,创建派生类defshow(self): #实现抽象方法print(self.value)c=Child(3) #实例化,创建派生类的对象c.modify(5)c.show() #输出:5189.2.4属性只读属性>>>classTest: def__init__(self,value): self.__value=value @property defvalue(self):#只读,无法修改和删除

returnself.__value199.2.4属性>>>t=Test(3)>>>t.value3>>>t.value=5#只读属性不允许修改值AttributeError:can'tsetattribute>>>t.v=5#动态增加新成员>>>t.v5>>>delt.v#动态删除成员>>>delt.value#试图删除对象属性,失败AttributeError:can'tdeleteattribute>>>t.value3209.2.4属性可读、可写属性>>>classTest:def__init__(self,value):self.__value=value def__get(self):returnself.__valuedef__set(self,v):self.__value=vvalue=property(__get,__set)defshow(self):print(self.__value)219.2.4属性>>>t=Test(3)>>>t.value#允许读取属性值3>>>t.value=5#允许修改属性值>>>t.value5>>>t.show()#属性对应的私有变量也得到了相应的修改5>>>delt.value#试图删除属性,失败AttributeError:can'tdeleteattribute229.2.4属性可读、可修改、可删除的属性。>>>classTest:def__init__(self,value):self.__value=valuedef__get(self):returnself.__valuedef__set(self,v):self.__value=vdef__del(self):delself.__valuevalue=property(__get,__set,__del)defshow(self):print(self.__value)239.2.4属性>>>t=Test(3)>>>t.show()3>>>t.value3>>>t.value=5>>>t.show()5>>>t.value5249.2.4属性>>>delt.value#删除属性>>>t.value#属性对应的私有数据成员已删除AttributeError:'Test'objecthasnoattribute'_Test__value'>>>t.show()AttributeError:'Test'objecthasnoattribute'_Test__value'>>>t.value=1#为对象动态增加属性和对应的私有数据成员>>>t.show()1>>>t.value1259.2.4属性例9-1

自定义矩形类,支持设置矩形的宽度和高度以及获取矩形的宽度、高度和面积。code\例9-1.py269.2.4属性classRectangle:def__init__(self,w,h):

#构造方法,名字是固定的self.width=w

#调用属性的setter方法进行赋值self.height=h@propertydefwidth(self):#读取属性的值时,自动调用这个方法returnself.__width@width.setterdefwidth(self,w):#修改属性的值时,自动调用这个方法assertisinstance(w,(int,float))andw>0,'矩形宽度必须大于0'self.__width=w@width.deleterdefwidth(self):#删除属性时,自动调用这个方法delself.__width279.2.4属性def__get_height(self):returnself.__heightdef__set_height(self,h):assertisinstance(h,(int,float))andh>0,'矩形宽度必须大于0'self.__height=hdef__del_height(self):delself.__height#使用property()函数定义属性#分别设置读取、修改、删除时调用的方法height=property(__get_height,__set_height,__del_height)@propertydefarea(self):returnself.__width

*

self.__height289.2.4属性r1=Rectangle(3,5)print(r1.area)r2=Rectangle(4,6)r2.width=5r2.height=7print(r2.area)299.3继承继承是用来实现代码复用和设计复用的机制,是面向对象程序设计的重要特性之一。设计一个新类时,如果可以继承一个已有的设计良好的类然后进行二次开发,无疑会大幅度减少开发工作量。在继承关系中,已有的、设计好的类称为父类或基类,新设计的类称为子类或派生类。派生类可以继承父类的公有成员,但是不能继承其私有成员。如果需要在派生类中调用基类的方法,可以使用内置函数super()或者通过“基类名.方法名()”的方式来实现这一目的。Python支持多继承,如果父类中有相同的方法名,而在子类中使用时没有指定父类名,则Python解释器将从左向右按顺序进行搜索。309.3继承例9-2

设计Person类,根据Person派生Teacher类,分别创建Person类与Teacher类的对象并查看对象信息。code\例9-2.py319.3继承classPerson:def__init__(self,name='',age=20,sex='man'):#通过调用方法进行初始化,这样可以对参数进行更好的控制self.set_name(name)self.set_age(age)self.set_sex(sex)defset_name(self,name):ifnotisinstance(name,str):raiseException('namemustbestring.')self.__name=namedefset_age(self,age):iftype(age)!=int:raiseException('agemustbeinteger.')self.__age=agedefset_sex(self,sex):ifsexnotin('man','woman'):raiseException('sexmustbe"man"or"woman"')self.__sex=sexdefshow(self):print(self.__name,self.__age,self.__sex,sep='\n')329.3继承#派生类classTeacher(Person):def__init__(self,name='',age=30,sex='man',department='Computer'):#调用基类构造方法初始化基类的私有数据成员super(Teacher,self).__init__(name,age,sex)#也可以这样初始化基类的私有数据成员#Person.__init__(self,name,age,sex)#调用自己的方法初始化派生类的数据成员self.set_department(department)#在派生类中新增加的方法defset_department(self,department):iftype(department)!=str:raiseException('departmentmustbeastring.')self.__department=department#覆盖了从父类中继承来的方法defshow(self):#先调用父类的同名方法,显示从父类中继承来的数据成员super(Teacher,self).show()#再显示派生类中的私有数据成员print(self.__department)339.3继承if__name__=='__main__':#创建基类对象zhangsan=Person('ZhangSan',19,'man')zhangsan.show()print('='*30)#创建派生类对象lisi=Teacher('Lisi',32,'man','Math')lisi.show()#调用继承的方法修改年龄lisi.set_age(40)lisi.show()349.3继承Python支持多继承。如果父类中有同名的方法,而在子类中使用时没有指定父类名,则Python解释器从左向右按顺序搜索每个父类中的成员,使用第一个匹配的成员。359.3继承例9-3

简单多继承场景中父类方法搜索顺序。classA:defshow(self):print('A')classB:defshow(self):print('B')classC:defshow(self):print('C')classD(B,A,C):passD().show() #输出:B369.4特殊成员Python类的特殊成员包括特殊属性和特殊方法,其特殊之处有两点:1)形式特殊,名字以双下画线开头且以双下画线结尾;2)名字、含义、功能是已经预定义好的,只能使用现有的特殊成员,不能随意增加。379.4.1特殊属性特殊属性是预定义好的表示特定含义的数据成员,名字以双下画线开头且以双下画线结尾。38特殊属性含义__base__第一个基类__bases__包含所有基类的元组__class__当前对象所属的类__dict__类命名空间的只读视图,形式为字典;通过对象访问时返回包含所有数据成员及其值的字典__doc__类的文档字符串,不存在时返回None__firstlineno__类定义在文件中的行号,Python3.13新增__module__类所在的模块名__mro__返回方法解析顺序(根据C3算法确定),形式为包含若干类名的元组__name__类的名字__qualname__类的限定名字__static_attributes__包含该类所有方法中通过self.X形式赋值的数据成员名称的元组,Python3.13新增9.4.1特殊属性classA:classB:def__init__(self,value):self.__value=valueb=A.B(3)print((A.B.__name__,A.B.__qualname__))print(b.__dict__)print(A.B.__firstlineno__)print(A.B.__mro__)39运行结果为:('B','A.B'){'_B__value':3}2(<class'__main__.A.B'>,<class'object'>)9.4.1特殊属性模块对象也有几个以双下画线开头和结尾的特殊属性,例如__name__返回模块的名字(直接运行时值为字符串'__main__',导入模块时值为模块文件主文件名),__package__返回模块所属的包名,__file__返回模块对应的文件完整路径(内置模块没有这个特殊属性),__path__返回模块对应的文件所在的文件夹路径,__doc__返回模块的文档字符串,__annotations__返回包含模块中已标注类型的变量名及其类型构成的字典,__dict__返回字典形式的模块命名空间。>>>importtkinter>>>tkinter.__file__'E:\\Python313\\Lib\\tkinter\\__init__.py'>>>tkinter.__path__['E:\\Python313\\Lib\\tkinter']>>>fromPILimportImage>>>Image.__package__'PIL'409.4.2特殊方法在Python中,不管类的名字是什么,构造方法的名字固定为__init__(),析构方法的名字固定为__del__(),分别用来在创建对象时进行必要的初始化和在释放对象时进行必要的清理工作。除了构造方法和析构方法之外,还有大量的特殊方法支持更多的功能。例如,自定义类对运算符和内置函数的支持就是通过重写特殊方法实现的。特殊方法名字与运算符或内置函数的对应关系是已经预定义好的,在自定义类时如果重写了某个特殊方法即可支持对应的运算符或内置函数,具体实现什么功能可以由程序员根据实际需要来定义,但不能随意增加新的特殊方法定义以及与运算符和内置函数的对应关系。419.4.2特殊方法42特殊方法功

明__init__()构造方法,创建对象时自动调用__init_subclass__()创建子类时自动调用__del__()析构方法,释放对象时自动调用__add__()二元运算符+,加法__sub__()二元运算符-,减法__mul__()*__truediv__()/__floordiv__()//__mod__()%__pow__()**__eq__()、

__ne__()、__lt__()、

__le__()、__gt__()、__ge__()==、!=、<、<=、>、>=9.4.2特殊方法43特殊方法功

明__lshift__()、__rshift__()<<、>>__and__()、__or__()、__invert__()、__xor__()&、|、~、^__iadd__()、__isub__()+=、-=,很多其他运算符也有与之对应的复合赋值运算符__pos__()一元运算符+,正号__neg__()一元运算符-,负号__contains__()in__radd__()、__rsub__反射加法、反射减法,一般与普通加法和减法具有相同的功能,但操作数的位置或顺序相反,很多其他运算符也有与之对应的反射运算符__abs__()与内置函数abs()对应__divmod__()与内置函数divmod()对应__format__()与内置函数format()对应9.4.2特殊方法44特殊方法功

明__hash__()与内置函数hash()对应__iter__()与内置函数iter()对应__len__()与内置函数len()对应__reversed__()与内置函数reversed()对应__round__()与内置函数round()对应__reduce__()使用pickle序列化对象时自动调用__repr__()与内置函数repr()对应,要求该方法必须返回字符串__str__()与内置函数str()对应,要求该方法必须返回字符串__getitem__()根据索引获取值__setitem__()根据索引赋值9.4.2特殊方法(1)Demo类中没有实现特殊方法__add__(),不支持加法运算符,试图使用加法运算符时引发异常。>>>classDemo:def__init__(self,value):self.__value=value

>>>d=Demo(3)>>>d+3TypeError:unsupportedoperandtype(s)for+:'Demo'and'int'459.4.2特殊方法(2)Demo类中实现了特殊方法__add__(),但没有实现特殊方法__radd__(),该类对象可以作为加法运算符的左运算数,但不能作为加法运算符的右运算符。>>>classDemo:def__init__(self,value):self.__value=valuedef__add__(self,another_value):returnself.__value+another_value

>>>dd=Demo(3)>>>dd+5 #Demo类的对象可以作为加法运算符的左运算数8>>>5+dd #试图作为右运算数时出错引发异常TypeError:unsupportedoperandtype(s)for+:'int'and'Demo'469.4.2特殊方法(3)Demo类中实现了特殊方法__add__()和__radd__()且共用同一段代码,该类对象既可以作为加法运算符的左运算数,也可以作为加法运算符的右运算数。>>>classDemo:def__init__(self,value):self.__v

温馨提示

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

最新文档

评论

0/150

提交评论