【文档说明】Python3基础教程第10章课件.pptx,共(49)页,132.712 KB,由小橙橙上传
转载请保留链接:https://www.ichengzhen.cn/view-2356.html
以下为本文档部分文字说明:
Python3基础教程第2版慕课版第10章面向对象本章主要内容:理解Python的面向对象定义和使用类对象的属性和方法类的继承模块中的类10.1理解Python的面向对象本节主要内容:面向对象的基本概念Pyth
on的类和类型Python中的对象10.1.1面向对象的基本概念面向对象的基本概念如下。类和对象:描述对象的属性和方法的集合称为类,它定义了同一类对象所共有的属性和方法。对象是类的实例,也称实例对象。方法:类中定义的函数,用于
描述对象的行为,也称方法成员。属性:类中在所有方法之外定义的变量(也称类中的顶层变量),用于描述对象的特点,也称数据成员。封装:类具有封装特性,其内部实现不应被外界知晓,只需要提供必要的接口供外部访问即可。实例化:创建一个类的实例对象。继承:从一个基类(也称父类或超类)
派生出一个子类时,子类拥有基类的属性和方法,称为继承。子类可以定义自己的属性和方法。重载(override):在子类中定义和父类方法同名的方法,称为子类对父类方法的重载,也称方法重写。多态:指不同类型对象的相同行为产
生不同的结果。和其它面向对象的程序设计语言相比,Python的面向对象机制更为简单。10.1.2Python的类和类型Python的类使用class语句来定义,类通常包含一系列的赋值语句和函数定义。赋值语句定义类的属性,
函数定义类的方法。在Python3中,类是一种自定义类型。Python的所有类型(包括自定义类型),都是内置类型type的实例对象,例如,内置的int、float、str等都是type类型的实例对象。type()函数可返回对象的类型,示
例代码>>>type(int)<class'type'>>>>type(float)<class'type'>>>>type(str)<class'type'>>>>classtest:#定义一个空类...p
ass...>>>type(test)<class'type'>10.1.3Python中的对象Python中的一切数据都是对象,如整数、小数、字符串、函数、模块等。例如,下面的代码分别测试了字符串、整数、逻辑值和函数的类型。
>>>type('abc')<class'str'>>>>type(123)<class'int'>>>>type(True)<class'bool'>>>>deffun():...pass...>>>type(
fun)<class'function'>Python中的对象可分为两种:类对象实例对象。类对象在执行class语句时创建。类对象是可调用的,类对象也称类实例。调用类对象会创建一个类的实例对象。类对象只有一个
,而类的实例对象可以有多个。类对象和实例对象分别拥有自己的命名空间,在各自的命名空间内使用对象的属性和方法。1.类对象类对象具有下列几个主要特点。Python在执行class语句时创建一个类对象和一个变量(与类同名),变量引用类对象。与def类似
,class也是可执行语句。导入类模块时,会执行class语句。类中的顶层赋值语句创建的变量是类的数据属性。类的数据属性用“对象名.属性名”格式来访问。类中的顶层def语句定义的函数是类的方法属性,用“对
象名.方法名()”格式来访问。类的数据属性由类的所有实例对象共享。实例对象可读取类的数据属性值,但不能通过赋值语句修改类的数据属性值。2.实例对象实例对象具有下列主要特点。实例对象通过调用类对象来创建。每个实例对象继承类对
象的所有属性,并获得自己的命名空间。实例对象拥有私有属性。通过赋值语句为实例对象的属性赋值时,如果该属性不存在,就会创建属于实例对象的私有属性。10.2定义和使用类本节主要内容:定义类使用类10.2.1定义类类定义的基本格式如下
。class类名:赋值语句赋值语句……def语句定义函数def语句定义函数……classtestclass:data=100defsetpdata(self,value):self.pdata=valuedefshowpdata(self):print('self.
pdata=',self.pdata)10.2.2使用类使用类对象可访问类的属性、创建实例对象,示例代码如下。>>>type(testclass)#测试类对象的类型<class'type'>>>>testclass
.data#访问类对象的数据属性100>>>x=testclass()#调用类对象创建第1个实例对象>>>type(x)#查看实例对象的类型,交互环境中的默认模块名称为__main__<class'__main__.testclass'>>>>x.set
pdata('abc’)#调用方法创建实例对象的数据属性pdata>>>x.showpdata()#调用方法显示实例对象的数据属性pdata的值self.pdata=abc>>>y=testclass()#调用类对象创建第2个实例对象>>>y.setpdata(12
3)#调用方法创建实例对象的数据属性pdata>>>y.showpdata()#调用方法显示实例对象的数据属性pdata的值self.pdata=12310.3对象的属性和方法本节主要内容:对象的属性对象的方法特殊属性和方法伪私有”属性和方法对象的初始化静态方法10.3.1对象
的属性在Python中,实例对象拥有类对象的所有属性。可以用dir()函数来查看对象的属性示例代码如下。>>>dir(testclass)#查看类对象的属性……>>>x=testclass()>>>dir(x)#查看实例对象的属性……1.共享属性类
对象的数据属性是全局的,并可通过实例对象来引用。testclass类顶层的赋值语句“data=100”定义了类对象的属性data,该属性可与所有实例对象共享示例代码如下。>>>x.data,y.dat
a#访问共享属性(100,100)>>>testclass.data=200#通过类对象修改共享属性>>>x.data,y.data#访问共享属性(200,200)需要注意的是,类对象的属性由所有实例对象共享,该属性的值只能通过类对象来修改。试图通过实例对象
对共享属性赋值时,实质是创建实例对象的私有属性,示例代码如下。>>>testclass.data=200#修改共享属性值>>>x.data,y.data,testclass.data#此时访问的都是共享属性值(200,200,200)>>>x.data='def’#此时为x创建私有
属性data>>>x.data,y.data,testclass.data#x.data访问的是x的私有属性data('def',200,200)>>>testclass.data=300>>>x.data,y.data,testclass.data('def',300,30
0)可用del语句删除对象的属性,示例代码如下。>>>delx.data#此时删除x的私有属性data>>>x.data#x.data访问类对象的共享属性300在以“实例对象.属性名”格式访问属性时:Python首先检查实例对象是否有匹配的私有属性,
如果有则返回该属性的值;如果没有,则进一步检查类对象是否有匹配的共享属性,如果有则返回该属性的值;如果也没有,则产生AttributeError异常。2.实例对象的私有属性实例对象的私有属性指以“实例对象.属性名=值”格式赋值时创
建的属性。“私有”强调属性只属于当前实例对象,对其他实例对象而言是不可见的。实例对象一开始只拥有继承自类对象的所有属性,没有私有属性。只有在给实例对象的属性赋值后,才会创建相应的私有属性示例代码如下。>>>x=testclass()#创建实例对象>>>x.pdata#
试图访问实例对象的属性,出错,属性不存在Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>AttributeError:'testclass'objec
thasnoattribute'pdata'>>>x.setpdata(123)#调用方法为属性赋值>>>x.pdata#赋值后,可以访问属性了1233.对象的属性是动态的Python总是在第一次给变量赋值时创建变量。对于类对象或实例对象而言,当给不存在的属性赋值时,Python为其创
建属性示例代码如下。>>>testclass.data2='abc'#赋值,为类对象添加属性>>>x.data3=[1,2]#赋值,为实例对象添加属性>>>testclass.data2,x.data2,x.data3#访问
属性('abc','abc',[1,2])>>>dir(testclass)#查看类对象属性列表['__class__','__delattr__',……,'data','data2','setpdata'
,'showpdata']>>>dir(x)['__class__','__delattr__',……,'data','data2','data3','pdata','setpdata','showpdata']可以看到,赋值操
作为对象添加了属性。而且,为类对象添加了属性时,实例对象也自动拥有了该属性。10.3.2对象的方法在通过实例对象访问方法时,Python会创建一个特殊对象:绑定方法对象,也称实例方法对象。此时,当前实例对象会作为一个参数传递给实例方法对象。所以在定义方法时,通常第
一个参数名称为self。使用self只是惯例,重要的是位置,完全可以用其他的名称来代替self。通过类对象访问方法时,不会将类对象传递给方法,应按方法定义的形参个数提供参数,这和通过实例对象访问方法有所区别>>>classtest:...defadd(a
,b):returna+b#定义方法,完成加法...defadd2(self,a,b):returna+b#定义方法,完成加法...>>>test.add(2,3)#通过类对象调用方法5>>>test.add2(2,3,4)·#通过类对象调用方法,此时参数self的值为27>>
>x=test()#创建实例对象>>>x.add(2,3)#出错,输出信息显示函数接收到3个参数Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:add()takes2positionalargu
mentsbut3weregiven>>>x.add2(2,3)#通过实例对象完成加法510.3.3特殊属性和方法Python会为类对象添加一系列特殊属性,常用特殊属性如下。__name__:返回为类的名称。__module__:返回类所在模块的名称。__di
ct__:返回包含类命名空间的字典。__bases__:返回包含基类的元组,按其在基类列表中的出现顺序排列。__doc__:返回类的文档字符串,如果没有则为None。__class__:返回类对象的类型名称,与type()的返回结果相
同。>>>classtest:pass#...>>>test.__name__'test'>>>test.__module__'__main__'>>>print(test.__dict__){'__module__':'__main__','__dict__’:……'test'objects>,
'__doc__':None}>>>test.__base__<class'object'>>>>print(test.__doc__)None>>>test.__class__<class'type'>Python会为类对象添加
一系列特殊方法,这些特殊方法在执行特定操作时被调用。可在定义类时定义这些方法,以取代默认方法,这称为方法的重载。类对象常用的特殊方法如下。__eq__():计算x==y时调用x.__eq__(y)。__
ge__():计算x>=y时调用x.__ge__(y)。__gt__():计算x>y时调用x.__gt__(y)。__le__():计算x<=y时调用x.__le__(y)。__lt__():计算x<y时调用x.__lt__(y)。__ne__():计算x!=y时
调用x.__ne__(y)。__format__():在内置函数format()和str.format()方法中格式化对象时调用,返回对象的格式化字符。__dir__():执行dir(x)时调用x.__dir__()。__delattr__():执行
delx.data时调用x.__delattr__(data)。__getattribute__():访问对象属性时调用。例如,a=x.data等同于a=x.__getattribute__(data)。__setattr__():为对象属性赋值时
调用。例如,x.data=a等同于x.__setattr__(a)。__hash__():调用内置函数hash(x)时,调用x.__hash__()。__new__():创建类的实例对象时调用。__init__():类的初始化函数。例如,x=te
st()语句在创建test类的实例对象时,首先调用__new__()创建一个新的实例对象,然后调用__init__()执行初始化操作。完成初始化之后再返回实例对象,同时建立变量x对实例对象的引用。__repr__():调用内置函数repr(x)的同时调用x.__repr__(
),返回对象的字符串表示。__str__():通过str(x)、print(x)以及在format()中格式化x时调用x.__str__(),返回对象的字符串表示。10.3.4“伪私有”属性和方法在Python中,可以以“类对象.属性名”或“实例对象.属性名”的格式在类的外部访问类的属性
。在面向对象技术理论中,这种方式破坏了类的封装特性。Python提供了一种折中的方法,即使用双下划线作为属性和方法名称的前缀,从而使这些属性和方法不能直接在类的外部使用。以双下划线作为名称前缀的属性和方法称为类的“伪私有”属性
和方法。>>>classtest:...data=100...__data2=200...defadd(a,b):...returna+b...def__sub(a,b):...returna-b...>>>test.data#访问普通属性100>>>test.add(2,3)#访问普通方法5>
>>test.__data2#访问“伪私有”属性,出错,属性不存在……>>>test.__sub(2,3)#“伪私有”方法,出错,方法不存在……Python在处理“伪私有”属性和方法名称时,会加上“_类名”作为双下划线前缀的前缀。之所以称为“伪私有”,指只要使用正确的名称,在类的外部也可
以访问“伪私有”属性和方法,示例代码如下。>>>test._test__data2#访问“伪私有”的属性200>>>test._test__sub(2,3)#访问“伪私有”的方法-1可使用dir()函数查看类对象的“伪
私有”属性和方法的真正名称,示例代码如下。>>>dir(test)['__class__','__delattr__',……,'_test__data2','_test__sub','add','data']10.3.5对象的初始化Python类的__init__()函数用于完成对象
的初始化。如果没有为类定义__init__()函数,Python会自动添加该函数。类对象在执行__new__()函数创建完实例对象时,会立即调用__init__()函数对实例对象执行初始化操作。示例代码如下。>>>classtest:...def__init__(se
lf,value):#定义对象初始化函数...self.data=value#为实例对象创建私有属性...print('实例对象初始化完毕')>>>x=test(100)#调用类对象创建实例对象,自动调用初始化函数实例对象初始化完毕>>>x.data#输出实例对象已初
始化的属性10010.3.6静态方法可使用@staticmethod将方法声明为静态方法。通过实例对象调用静态方法时,不会像普通方法一样将实例对象本身作为隐含的第一个参数传递给方法。通过类对象和实例对象调用静态方法的效果完全相同。示例代码如下。>>>classtes
t:...@staticmethod#声明下面的add()为静态方法...defadd(a,b):returna+b...>>>test.add(2,3)#通过类对象调用静态方法5>>>x=test()#创建实例对象>>>x.add(3,5)#通过实例对象调用静态方法810.4类的继承
本节主要内容:简单继承在子类中定义属性和方法调用超类的初始化函数多重继承10.4.1简单继承通过继承来定义新类的基本格式如下。class子类名(超类名):子类代码>>>classsupper_class:#定义超类...data=100...__data2=200...de
fshowinfo(self):...print('超类showinfo()方法中的输出信息')...def__showinfo(self):...print('超类__showinfo()方法中的输出信息')...>>>classsub_class(supper_class):pa
ss#定义空的子类,pass表示空操作...>>>supper=dir(supper_class)#获得超类属性和方法列表>>>sub=dir(sub_class)#获得子类属性和方法列表>>>supper==sub#True,说明超类和子类的拥有的属性和方法相同Tr
ue>>>sub_class.data#访问继承的属性100>>>sub_class._supper_class__data2#访问继承的属性200>>>x=sub_class()#创建子类的实例对象>>>x.showinfo()#调用继承的方法超类showinfo()方法
中的输出信息>>>x._supper_class__showinfo()#调用继承的方法超类__showinfo()方法中的输出信息10.4.2在子类中定义属性和方法Python允许在子类中定义属性和方法。子类定义的属性和方法会覆盖超类中的同名属性和方法。在子类中定义与
超类方法同名的方法,称为方法的重载,>>>classsupper:#定义超类...data1=10...data2=20...defshow1(self):...print('在超类的show1()方法中的输出')...defshow2(self):...print('在超类
的show2()方法中的输出')...>>>classsub(supper):#定义子类...data1=100#覆盖超类的同名变量...defshow1(self):#重载超类的同名方法...print('在子类的show1()方法中的输出
')...>>>[xforxindir(sub)ifnotx.startswith('__')]#显示子类非内置属性['data1','data2','show1','show2']>>>x=sub()#创建子类实例对象>>>x.data1,x.data2#data1是子类自定义的属性,data
2是继承的属性(100,20)>>>x.show1()#调用子类自定义方法在子类的show1()方法中的输出>>>x.show2()#调用继承的方法在超类的show2()方法中的输出在子类中,可用super()函数返回超类的类对象,从而通过它访问超类的方法。也可直接使用类对象
调用超类的方法,示例代码如下。>>>classsub(supper):#定义子类...data1=100...defshow1(self):...print('在子类的show1()方法中的输出')...test.show1(self)#调用超类的方法...supe
r().show2(self)#调用超类的方法...>>>x=sub()>>>x.show1()在子类的show1()方法中的输出在超类的show1()方法中的输出在超类的show2()方法中的输出10.4.3调用超类的初始化函数在子类的初始化函数中,通常应调用超类的初始化函数,
Python不会自动调用超类的初始化函数,示例代码如下。>>>classtest:#定义超类...def__init__(self,a):...self.supper_data=a...>>>classsub(test):#定义子类...def__init__(self,a,b):
#定义子类的构造函数...self.sub_data=a...super().__init__(b)#调用超类的初始化函数...>>>x=sub(10,20)#创建子类实例对象>>>x.supper_data#访问继承的属性20>>>x.sub_data#
访问自定义属性1010.4.4多重继承多重继承指子类可以同时继承多个超类。如果超类中存在同名的属性或方法,Python按照从左到右的顺序在超类中搜索方法>>>classsupper1:#定义超类1...data1=10...data2=20...defsho
w1(self):...print('在超类supper1的show1()方法中的输出')...defshow2(self):...print('在超类supper1的show2()方法中的输出')...>>>classsupper2:#定义超类2...data2=300..
.data3=400...defshow2(self):...print('在超类supper2的show2()方法中的输出')...defshow3(self):...print('在超类supper2的show3()方法中的输出')...>>>c
lasssub(supper1,supper2):pass#定义空的子类...>>>[xforxindir(sub)ifnotx.startswith('__')]#显示子类非内置属性['data1','data2','data3','show1'
,'show2','show3']>>>x=sub()#创建子类的实例对象>>>x.data1,x.data2,x.data3#访问继承的属性(10,20,400)>>>x.show1()#调用继承的方法在超类supper1的show1()方法中的输出>>>x.show2()#调用继承的
方法在超类supper1的show2()方法中的输出>>>x.show3()#调用继承的方法在超类supper2的show3()方法中的输出10.5模块中的类可以将模块中的类导入到当前模块使用。导入的类是模块对象的一个属性,与模块中的函数类似。在模块文件classlib.py中定义了一个
test类,代码如下。classtest:data1=100defset(self,a):self.data2=adefshow(self):print('data1=%sdata2=%s'%(self.data1,self.data2))if__name__=='__ma
in__':print('模块独立运行的自测试输出:')x=test()x.set([1,2,3,4])x.show()模块可以独立运行,运行时输出结果如下。模块独立运行的自测试输出:data1=100data2=[1,2,3,4]在交互模
式下用import语句导入classlib.py,使用test类,示例代码如下。>>>importclasslib#导入模块>>>x=classlib.test()#调用类对象创建实例对象>>>x.data1#访问类的共享属性data1100>>>x.data1='Pyth
on'#为data1赋值,为实例对象创建私有属性>>>x.set(200)#调用类方法设置属性值>>>x.show()#调用类方法显示属性值data1=Pythondata2=20010.6综合实例在IDLE创建一个Python程序,可将输入的姓名和年龄以对象的形式存入文件,
如果已存在姓名,则用新的年龄修改原数据。