深入讲解Python中面向对象编程的相关知识
Python从第一天开始就是面向对象的语言。正因为如此,创建和使用类和对象是非常地容易。本章将帮助您在使用Python面向对象编程的技术方面所有提高。
如果没有任何以往面向对象(OO)的编程的经验,那么可能要了解一些基本的入门课程就可以了,或者至少某种形式的教程,让你有了解基本概念。
但是,这里会比较少地介绍面向对象编程(OOP):
OOP术语概述
- 类:用户定义的原型对象,它定义了一套描述类的任何对象的属性。属性是数据成员(类变量和实例变量)和方法,通过点符号访问。
- 类变量:这是一个类的所有实例共享的变量。类变量在类,但外面的任何类的方法定义。类变量不被用作经常作为实例变量。
- 数据成员:保存与类和对象关联的数据的类变量或实例变量。
- 函数重载:一个以上的行为特定功能的分配。执行的操作所涉及的对象(自变量)的类型不同而不同。
- 实例变量:所定义的方法内,只属于一个类的当前实例的变量。
- 继承:类的特点,即都是由它派生其他类的转移。
- 实例:某一类的一个单独对象。属于类Circle一个obj对象,例如,是类Circle的一个实例。
- 实例化:创建一个类的实例。
- Method:一种特殊的函数,函数在类定义中定义。
- 对象:这是由它的类中定义的数据结构的唯一实例。一个对象包括两个数据成员(类变量和实例变量)和方法。
- 运算符重载:一个以上的函数功能,特定的操作符分配。
创建类:
类语句将创建一个新的类定义。类的名称紧跟在关键字class后跟一个冒号,如下所示:
classClassName: 'Optionalclassdocumentationstring' class_suite
类有一个文档字符串,它可以通过类名.__doc__访问。
class_suite由所有定义的类成员,数据属性与函数组件的语句。
例子
下面是一个简单的Python类的例子:
classEmployee: 'Commonbaseclassforallemployees' empCount=0 def__init__(self,name,salary): self.name=name self.salary=salary Employee.empCount+=1 defdisplayCount(self): print"TotalEmployee%d"%Employee.empCount defdisplayEmployee(self): print"Name:",self.name,",Salary:",self.salary
empCount是一个类变量,其值将是这个类的所有实例共享。这可以从类中或外部进行访问,访问形式为Employee.empCount。
第一个方法__init__()是一种特殊的方法,这就是所谓的类构造函数或当创建该类的一个新实例Python调用的初始化方法。
声明就像正常函数中一样,不同的是第一个参数到每个方法是类的方法。Python增加了self参数列表;不需要把调用的方法都它列入。
创建实例对象:
要创建一个类的实例,调用类名并传递任何参数给__init__方法接收。
"ThiswouldcreatefirstobjectofEmployeeclass" emp1=Employee("Zara",2000) "ThiswouldcreatesecondobjectofEmployeeclass" emp2=Employee("Manni",5000)
访问属性:
可以访问使用点运算符来访问对象的属性。而类变量使用类名来访问,如下所示:
emp1.displayEmployee() emp2.displayEmployee() print"TotalEmployee%d"%Employee.empCount
现在,把所有的概念放在一起:
#!/usr/bin/python classEmployee: 'Commonbaseclassforallemployees' empCount=0 def__init__(self,name,salary): self.name=name self.salary=salary Employee.empCount+=1 defdisplayCount(self): print"TotalEmployee%d"%Employee.empCount defdisplayEmployee(self): print"Name:",self.name,",Salary:",self.salary "ThiswouldcreatefirstobjectofEmployeeclass" emp1=Employee("Zara",2000) "ThiswouldcreatesecondobjectofEmployeeclass" emp2=Employee("Manni",5000) emp1.displayEmployee() emp2.displayEmployee() print"TotalEmployee%d"%Employee.empCount
当执行上面的代码,产生以下结果:
Name:Zara,Salary:2000 Name:Manni,Salary:5000 TotalEmployee2
在任何时候可以添加,删除或修改类和对象的属性:
emp1.age=7#Addan'age'attribute. emp1.age=8#Modify'age'attribute. delemp1.age#Delete'age'attribute.
除了使用正常的语句来访问属性,可以使用以下函数:
- getattr(obj,name[,default]):访问对象的属性。
- hasattr(obj,name):检查一个属性是否存在。
- setattr(obj,name,value):设置一个属性。如果属性不存在,那么它将被创建。
- delattr(obj,name):要删除一个属性。
hasattr(emp1,'age')#Returnstrueif'age'attributeexists getattr(emp1,'age')#Returnsvalueof'age'attribute setattr(emp1,'age',8)#Setattribute'age'at8 delattr(empl,'age')#Deleteattribute'age'
内置的类属性:
每个Python类会继续并带有内置属性,他们可以使用点运算符像任何其他属性一样来访问:
- __dict__:字典包含类的命名空间。
- __doc__:类的文档字符串,或None如果没有定义。
- __name__:类名称。
- __module__:在类中定义的模块名称。此属性是在交互模式其值为“__main__”。
- __bases__:一个可能是空的元组包含了基类,其在基类列表出现的顺序。
对于上面的类,尝试访问这些属性:
#!/usr/bin/python classEmployee: 'Commonbaseclassforallemployees' empCount=0 def__init__(self,name,salary): self.name=name self.salary=salary Employee.empCount+=1 defdisplayCount(self): print"TotalEmployee%d"%Employee.empCount defdisplayEmployee(self): print"Name:",self.name,",Salary:",self.salary print"Employee.__doc__:",Employee.__doc__ print"Employee.__name__:",Employee.__name__ print"Employee.__module__:",Employee.__module__ print"Employee.__bases__:",Employee.__bases__ print"Employee.__dict__:",Employee.__dict__
当执行上面的代码,产生以下结果:
Employee.__doc__:Commonbaseclassforallemployees Employee.__name__:Employee Employee.__module__:__main__ Employee.__bases__:() Employee.__dict__:{'__module__':'__main__','displayCount': <functiondisplayCountat0xb7c84994>,'empCount':2, 'displayEmployee':<functiondisplayEmployeeat0xb7c8441c>, '__doc__':'Commonbaseclassforallemployees', '__init__':<function__init__at0xb7c846bc>}
销毁对象(垃圾回收):
Python的删除不需要的对象(内建类型或类的实例),自动释放内存空间。由Python定期回收的内存块不再使用的过程被称为垃圾收集。
Python的垃圾回收器在程序执行过程中运行,当一个对象的引用计数为零时触发。一个对象的引用计数改变为指向它改变别名的数量。
当它分配一个新的名字或放置在容器(列表,元组或字典)的对象的引用计数增加。当对象的引用计数减少使用del删除,其基准被重新分配,或者它的引用超出范围。当一个对象的引用计数变为零,Python会自动地收集它。
a=40#Createobject<40> b=a#Increaseref.countof<40> c=[b]#Increaseref.countof<40> dela#Decreaseref.countof<40> b=100#Decreaseref.countof<40> c[0]=-1#Decreaseref.countof<40>
当垃圾回收器销毁孤立的实例,并回收其空间一般不会注意到。但是,一个类可以实现特殊方法__del__(),称为析构函数被调用时,该实例将被摧毁。这个方法可以用于清理所用的一个实例的任何非内存资源。
例子:
__del__()析构函数打印实例,它即将被销毁的类名:
#!/usr/bin/python classPoint: def__init(self,x=0,y=0): self.x=x self.y=y def__del__(self): class_name=self.__class__.__name__ printclass_name,"destroyed" pt1=Point() pt2=pt1 pt3=pt1 printid(pt1),id(pt2),id(pt3)#printstheidsoftheobejcts delpt1 delpt2 delpt3
当执行上面的代码,它产生以下结果:
308340132430834013243083401324 Pointdestroyed
注意:理想情况下,应该定义类的单独的文件,那么应该使用import语句将其导入主程序文件。详细请查看Python-模块章节,导入模块和类的更多细节。
类继承:
不用从头开始,可以通过上面列出的括号父类的新类名后,从一个已经存在的类派生它创建一个类。
子类继承父类的属性,可以使用父类的这些属性,就好像它们是在子类中定义的一样。子类也可以覆盖父类的数据成员和方法。
语法
派生类的声明很像它们的父类;从基类的列表后给出类名继承:
classSubClassName(ParentClass1[,ParentClass2,...]): 'Optionalclassdocumentationstring' class_suite
例子
#!/usr/bin/python classParent:#defineparentclass parentAttr=100 def__init__(self): print"Callingparentconstructor" defparentMethod(self): print'Callingparentmethod' defsetAttr(self,attr): Parent.parentAttr=attr defgetAttr(self): print"Parentattribute:",Parent.parentAttr classChild(Parent):#definechildclass def__init__(self): print"Callingchildconstructor" defchildMethod(self): print'Callingchildmethod' c=Child()#instanceofchild c.childMethod()#childcallsitsmethod c.parentMethod()#callsparent'smethod c.setAttr(200)#againcallparent'smethod c.getAttr()#againcallparent'smethod
当执行上面的代码,产生以下结果:
Callingchildconstructor Callingchildmethod Callingparentmethod Parentattribute:200
类似的方式,可以按如下继承多个父类的类:
classA: #defineyourclassA .....
classB: #defineyourcalssB .....
classC(A,B): #subclassofAandB .....