Python一直是面向对象的语言,因为它存在。因此,创建和使用类和对象是非常容易的。本章帮助您成为使用Python面向对象编程支持的专家。
如果您以前没有面向对象(OO)编程的经验,您可能需要查阅介绍性课程或至少一个教程,以便掌握基本概念。
然而,这里是面向对象编程(OOP)的小型引入,为您带来速度 -
OOP术语概述
类:用于定义一组属性的对象的用户定义prototype,用于表征该类的任何对象。属性是通过点符号访问的数据成员(类变量和实例变量)和方法。
类变量:由类的所有实例共享的变量。类变量在类中定义,但在类的任何方法之外。类变量不像实例变量那样频繁使用。
数据成员:保存与类及其对象关联的数据的类变量或实例变量。
函数重载:将多个行为分配给特定函数。执行的操作因涉及的对象或参数的类型而异。
实例变量:在方法中定义并仅属于类的当前实例的变量。
继承:将类的特征传递给从其派生的其他类。
实例:某个类的单个对象。例如,属于类Circle的对象obj是类Circle的实例。
实例化:创建一个类的实例。
方法:在类定义中定义的一种特殊类型的函数。
对象:由其类定义的数据结构的唯一实例。对象包括数据成员(类变量和实例变量)和方法。
运算符重载:将多个函数分配给特定的运算符。
创建类
在类的语句创建一个新的类定义。类的名称紧跟在关键字类后跟冒号如下 -
classClassName:"Optional class documentation string"class_suite
该类有一个文档字符string,可以通过ClassName .__ doc__访问。
class_suite由所有定义类成员,数据属性和功能组件的语句。
例
以下是一个简单的Python类的例子 -
classEmployee:"Common base class for all employees"empCount=0def__init__(self,name,salary):self.name=nameself.salary=salaryEmployee.empCount+=1defdisplayCount(self):print"Total Employee %d"%Employee.empCountdefdisplayEmployee(self):print"Name : ",self.name,", Salary: ",self.salary
变量empCount是一个类变量,其值在此类的所有实例之间共享。这可以从类或类外面的Employee.empCount访问。
第一种方法__init __()是一种特殊的方法,当您创建此类的新实例时,该方法称为Python构造函数或初始化方法。
您声明其他类方法,如正常函数,但每个方法的第一个参数是self。Python将自我参数添加到列表中;您调用方法时不需要包含它。
创建实例对象
要创建类的实例,可以使用类名调用该类,并传递其__init__方法接受的任何参数。
"This would create first object of Employee class"emp1=Employee("Zara",2000)"This would create second object of Employee class"emp2=Employee("Manni",5000)
访问属性
您可以使用带有对象的点运算符来访问对象的属性。使用类名称访问类变量,如下所示:
emp1.displayEmployee()emp2.displayEmployee()print"Total Employee %d"%Employee.empCount
现在把所有的概念放在一起 -
#!/usr/bin/pythonclassEmployee:"Common base class for all employees"empCount=0def__init__(self,name,salary):self.name=nameself.salary=salaryEmployee.empCount+=1defdisplayCount(self):print"Total Employee %d"%Employee.empCountdefdisplayEmployee(self):print"Name : ",self.name,", Salary: ",self.salary"This would create first object of Employee class"emp1=Employee("Zara",2000)"This would create second object of Employee class"emp2=Employee("Manni",5000)emp1.displayEmployee()emp2.displayEmployee()print"Total Employee %d"%Employee.empCount
当执行上述代码时,输出结果如下-
Name:Zara,Salary:2000Name:Manni,Salary:5000TotalEmployee2
您可以随时添加,删除或修改类和对象的属性 -
emp1.age=7# Add an "age" attribute.emp1.age=8# Modify "age" attribute.delemp1.age# Delete "age" attribute.
而不是使用普通语句访问属性,您可以使用以下函数 -
GETATTR(OBJ,名称[,默认]):访问对象的属性。
hasattr(OBJ,名):检查属性的存在与否。
SETATTR(OBJ,名称,值):设置一个属性。如果属性不存在,那么它将被创建。
delattr(OBJ,名):要删除属性。
hasattr(emp1,"age")# Returns true if "age" attribute existsgetattr(emp1,"age")# Returns value of "age" attributesetattr(emp1,"age",8)# Set attribute "age" at 8delattr(empl,"age")# Delete attribute "age"
内置类属性
每个Python类保持以下内置属性,并且可以像任何其他属性一样使用点运算符访问它们 -
__dict__:包含该类的命名空间的字典。
__doc__:类文档字符string或无,如果未定义。
__name__:类名。
__module__:定义类的模块名称。此属性在交互模式下为“__main__”。
__bases__:一个包含基类的空元组,按照它们在基类列表中出现的顺序。
对于上述类,我们尝试访问所有这些属性 -
#!/usr/bin/pythonclassEmployee:"Common base class for all employees"empCount=0def__init__(self,name,salary):self.name=nameself.salary=salaryEmployee.empCount+=1defdisplayCount(self):print"Total Employee %d"%Employee.empCountdefdisplayEmployee(self):print"Name : ",self.name,", Salary: ",self.salaryprint"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__: Common base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
Employee.__dict__: {"__module__": "__main__", "displayCount":
, "empCount": 2,
"displayEmployee": ,
"__doc__": "Common base class for all employees",
"__init__": }
销毁物品(垃圾收集)
Python会自动删除不需要的对象(内置类型或类实例)以释放内存空间。Python定期回收不再使用的内存块的过程称为垃圾回收。
Python的垃圾收集器在程序执行期间运行,并且当对象的引用计数达到零时触发。对象的引用计数随着指向它的别名数量的变化而变化。
当对象的引用计数被分配一个新的名称或放置在一个容器(列表,元组或字典)中时,它的引用计数就会增加。当它与删除的对象的引用计数减少德尔,其基准被重新分配,或它引用超出范围。当对象的引用计数达到零时,Python会自动收集它。
a=40# Create object <40>b=a# Increase ref. count of <40>c=[b]# Increase ref. count of <40>dela# Decrease ref. count of <40>b=100# Decrease ref. count of <40>c[0]=-1# Decrease ref. count of <40>
通常情况下,垃圾回收器会破坏一个孤立的实例并回收其空间。但是一个类可以实现一个称为析构函数的特殊方法__del __(),该方法在实例即将被销毁时被调用。此方法可用于清理实例使用的任何非内存资源。
例
这个__del __()析构函数打印要被销毁的实例的类名 -
#!/usr/bin/pythonclassPoint:def__init(self,x=0,y=0):self.x=xself.y=ydef__del__(self):class_name=self.__class__.__name__printclass_name,"destroyed"pt1=Point()pt2=pt1
pt3=pt1printid(pt1),id(pt2),id(pt3)# prints the ids of the obejctsdelpt1delpt2delpt3
当执行上述代码时,输出结果如下-
308340132430834013243083401324Pointdestroyed
注意:理想情况下,您应该在单独的文件中定义您的类,然后使用import语句将它们导入主程序文件。
类继承
而不是从头开始,您可以通过在新类名后面的括号中列出父类来从预先存在的类派生它来创建一个类。
子类继承其父类的属性,您可以像子类中定义的一样使用这些属性。子类也可以从父代替代数据成员和方法。
用法
派生类被声明为很像他们的父类;然而,继承的基类的列表在类名之后给出 -
classSubClassName(ParentClass1[,ParentClass2,...]):"Optional class documentation string"class_suite
例
#!/usr/bin/pythonclassParent:# define parent classparentAttr=100def__init__(self):print"Calling parent constructor"defparentMethod(self):print"Calling parent method"defsetAttr(self,attr):Parent.parentAttr=attrdefgetAttr(self):print"Parent attribute :",Parent.parentAttrclassChild(Parent):# define child classdef__init__(self):print"Calling child constructor"defchildMethod(self):print"Calling child method"c=Child()# instance of childc.childMethod()# child calls its methodc.parentMethod()# calls parent"s methodc.setAttr(200)# again call parent"s methodc.getAttr()# again call parent"s method
当执行上述代码时,输出结果如下-
Callingchild constructorCallingchild methodCallingparent methodParentattribute:200
类似的方式,您可以从多个父类驱动一个类,如下所示:
classA:# define your class A.....classB:# define your class B.....classC(A,B):# subclass of A and B.....
您可以使用issubclass()或isinstance()函数来检查两个类和实例之间的关系。
issubclass(子,SUP)如果给定的子类布尔函数返回真子确实是超类的子类SUP。
的isinstance(OBJ,班)的布尔函数,如果返回trueOBJ是类的实例类或类是一个子类的实例
覆盖方法
您可以随时覆盖您的父类方法。覆盖父方法的一个原因是因为您可能需要在子类中使用特殊或不同的功能。
例
#!/usr/bin/pythonclassParent:# define parent classdefmyMethod(self):print"Calling parent method"classChild(Parent):# define child classdefmyMethod(self):print"Calling child method"c=Child()# instance of childc.myMethod()# child calls overridden method
当执行上述代码时,输出结果如下-
Callingchild method
基本重载方法
下表列出了您可以在自己的类中覆盖的一些通用功能 -
SN方法,说明和样品呼叫
1__init__(self [,args ...])
构造函数(带任意可选参数)
示例调用:obj = className(args)
2__del __(self)
析构函数,删除一个对象
Sample Call:del obj
3__repr __(self)可
评估字符string表示
样本调用:repr(obj)
4__str __(self)可
打印的字符string表示
样本调用:str(obj)
5__cmp__(self,x)
对象比较
示例调用:cmp(obj,x)
重载运算符
假设你已经创建了一个Vector类来表示二维向量,当你使用加号运算符来添加它们时会发生什么?很可能Python会对你大喊大叫。
但是,您可以在类中定义__add__方法来执行向量加法,然后加运算符将按照期望行为 -
例
#!/usr/bin/pythonclassVector:def__init__(self,a,b):self.a=aself.b=bdef__str__(self):return"Vector (%d, %d)"%(self.a,self.b)def__add__(self,other):returnVector(self.a+other.a,self.b+other.b)v1=Vector(2,10)v2=Vector(5,-2)printv1+v2
当执行上述代码时,输出结果如下-
Vector(7,8)
数据隐藏
对象的属性在类定义之外可能或不可见。您需要使用双下划线前缀命名属性,然后这些属性不会直接对外部人员可见。
例
#!/usr/bin/pythonclassJustCounter:__secretCount=0defcount(self):self.__secretCount+=1printself.__secretCount
counter=JustCounter()counter.count()counter.count()printcounter.__secretCount
当执行上述代码时,输出结果如下-
12Traceback(most recent calllast):File"test.py",line12,inprintcounter.__secretCountAttributeError:JustCounterinstance hasnoattribute"__secretCount"
Python通过内部更改名称来包含类名称来保护这些成员。您可以访问object._className__attrName等属性。如果您将最后一行替换为以下,那么它适用于您 -
.........................printcounter._JustCounter__secretCount
当执行上述代码时,输出结果如下-
1
2
2