自从它存在以来,Python一直是面向对象的语言.因此,创建和使用类和对象非常简单.本章帮助您成为使用Python面向对象编程支持的专家.
如果您以前没有任何面向对象(OO)编程经验,您可能需要咨询关于它的入门课程或至少是某种教程,以便掌握基本概念.
但是,这里是面向对象编程(OOP)的一个小介绍.帮助你减去;
OOP术语概述
Class : 用户定义的对象原型,它定义了一组表征该类任何对象的属性.属性是数据成员(类变量和实例变量)和方法,可通过点表示法访问.
类变量 : 由类的所有实例共享的变量.类变量在类中定义,但在类的任何方法之外.类变量的使用频率与实例变量不同.
数据成员 : 包含与类及其对象关联的数据的类变量或实例变量.
函数重载 : 为特定函数分配多个行为.执行的操作因所涉及的对象或参数类型而异.
实例变量 : 在方法内定义的变量,仅属于类的当前实例.
继承 : 将类的特征转移到从中派生的其他类.
实例 : 某个班级的个别对象.例如,属于Circle类的对象obj是Circle类的实例.
Instantiation : 创建类的实例.
方法 : 一种在类定义中定义的特殊函数.
对象 : 由其类定义的数据结构的唯一实例.对象包括数据成员(类变量和实例变量)和方法.
运算符重载 : 为特定运算符分配多个函数.
创建类
class 语句创建一个新的类定义.该类的名称紧跟在关键字 class 之后,后跟冒号,如下 :
class ClassName: 'Optional class documentation string' class_suite
该课程有文档字符串,可以通过 ClassName .__ doc __ 访问.
class_suite 由定义类成员,数据属性和函数的所有组件语句组成.
示例
以下是一个简单的Python类的示例 :
class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print ("Total Employee %d" % Employee.empCount) def displayEmployee(self): print ("Name : ", self.name, ", Salary: ", self.salary)
变量 empCount 是一个类变量,其值在所有之间共享本课程中的a个实例.这可以从类内部或类外部作为 Employee.empCount 访问.
第一种方法 __ init __( )是一种特殊的方法,它被称为类构造函数或初始化方法,当你创建这个类的新实例时Python会调用它.
你声明其他类方法,如普通函数,但每个方法的第一个参数是 self . Python将 self 参数添加到列表中;调用方法时不需要包含它.
创建实例对象
要创建类的实例,可以使用类名调用该类,并传入其 __ init __ 方法接受的任何参数.
This would create first object of Employee classemp1 = Employee("Zara", 2000)This would create second object of Employee classemp2 = Employee("Manni", 5000)
访问属性
使用点运算符和对象访问对象的属性.使用类名访问类变量如下 :
emp1.displayEmployee()emp2.displayEmployee()print ("Total Employee %d" % Employee.empCount)
现在,将所有概念放在一起&减去;
#!/usr/bin/python3class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print ("Total Employee %d" % Employee.empCount) def displayEmployee(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: 5000Total Employee 2
您可以随时添加,删除或修改类和对象的属性;
emp1.salary = 7000 # Add an 'salary' attribute.emp1.name = 'xyz' # Modify 'age' attribute.del emp1.salary # Delete 'age' attribute.
您可以使用以下函数 :
getattr(obj,name [,default]) : 访问对象的属性.
hasattr(obj,name) : 检查属性是否存在.
setattr(obj,name,value) : 设置属性.如果属性不存在,那么它将被创建.
delattr(obj,name) : 删除属性.
hasattr(emp1, 'salary') # Returns true if 'salary' attribute existsgetattr(emp1, 'salary') # Returns value of 'salary' attributesetattr(emp1, 'salary', 7000) # Set attribute 'salary' at 7000delattr(emp1, 'salary') # Delete attribute 'salary'
内置类属性
每一个Python类保持跟随内置属性,并且可以使用点运算符访问它们,就像任何其他属性 :
__ dict __ : 包含类名称空间的字典.
__ doc __ : 类文档字符串或无,如果未定义.
__ name __ : 班级名称.
__ module __ : 定义类的模块名称.此属性在交互模式下为"__main__".
__ bases __ : 一个可能为空的元组,包含基类,按它们在基类列表中出现的顺序排列.
对于上面的类让我们尝试访问所有这些属性 :
#!/usr/bin/python3class Employee: 'Common base class for all employees' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print ("Total Employee %d" % Employee.empCount) def displayEmployee(self): print ("Name : ", self.name, ", Salary: ", self.salary)emp1 = Employee("Zara", 2000)emp2 = Employee("Manni", 5000)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__: Common base class for all employeesEmployee.__name__: EmployeeEmployee.__module__: __main__Employee.__bases__: (,)Employee.__dict__: { 'displayCount': , '__module__': '__main__', '__doc__': 'Common base class for all employees', 'empCount': 2, '__init__': , 'displayEmployee': , '__weakref__': , '__dict__': }
销毁对象(垃圾收集)
Python删除不需要的对象(内置类型或类实例)自动释放内存空间. Python定期回收不再使用的内存块的过程称为垃圾收集.
Python的垃圾收集器在程序执行期间运行,并在对象的引用计数达到零时触发.对象的引用计数随着指向它的别名数量的变化而变化.
对象的引用计数在分配新名称或放在容器中时会增加(列表,元组或字典).当使用 del 删除对象的引用计数时,对象的引用计数会减少,其引用将被重新分配,或者其引用超出范围.当对象的引用计数达到零时,Python会自动收集它.
a = 40 # Create object <40>b = a # Increase ref. count of <40> c = [b] # Increase ref. count of <40> del a # Decrease ref. count of <40>b = 100 # Decrease ref. count of <40> c[0] = -1 # Decrease ref. count of <40>
您通常不会注意到垃圾收集器何时销毁孤立实例并回收其空间.但是,类可以实现特殊方法 __ del __(),称为析构函数,在实例即将被销毁时调用.此方法可用于清除实例使用的任何非内存资源.
示例
此__del __()析构函数打印类名即将被销毁和减去的实例;
#!/usr/bin/python3class Point: def __init__( self, x=0, y=0): self.x = x self.y = y def __del__(self): class_name = self.__class__.__name__ print (class_name, "destroyed")pt1 = Point()pt2 = pt1pt3 = pt1print (id(pt1), id(pt2), id(pt3)) # prints the ids of the obejctsdel pt1del pt2del pt3
执行上述代码时,会产生以下结果 :
140338326963984 140338326963984 140338326963984Point destroyed
注意 : 理想情况下,您应该在单独的文件中定义类,然后使用 import 语句将它们导入主程序文件中.
在上面的示例中,假设Point类的定义包含在 point.py 中,其中没有其他可执行代码.
#!/usr/bin/python3import pointp1 = point.Point()
类继承
您可以通过在新类名后面的括号中列出父类,而不是从头开始,通过从预先存在的类派生它来创建类.
子类继承其父类的属性,您可以使用这些属性,就好像它们是在子类中定义的一样.子类也可以覆盖父类的数据成员和方法.
语法
派生类的声明与其父类非常相似;但是,在类名和减号之后给出了要继承的基类列表;
class SubClassName (ParentClass1[, ParentClass2, ...]): 'Optional class documentation string' class_suite
示例
#!/usr/bin/python3class Parent: # define parent class parentAttr = 100 def __init__(self): print ("Calling parent constructor") def parentMethod(self): print ('Calling parent method') def setAttr(self, attr): Parent.parentAttr = attr def getAttr(self): print ("Parent attribute :", Parent.parentAttr)class Child(Parent): # define child class def __init__(self): print ("Calling child constructor") def childMethod(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
执行上面的代码时,它产生以下结果 :
Calling child constructorCalling child methodCalling parent methodParent attribute : 200
以类似的方式,您可以从多个父类驱动一个类,如下所示;
class A: # define your class A.....class B: # define your calss B.....class C(A, B): # subclass of A and B.....
您可以使用issubclass()或isinstance()函数来检查两个类和实例的关系.
issubclass(sub,sup)如果给定的子类 sub 确实是超类 sup 的子类,则布尔函数返回True.
isinstance(obj,Class)布尔函数返回True,如果 obj 是类类的实例或是Class的子类的实例
重写方法
你总是可以覆盖您的父类方法.覆盖父方法的一个原因是您可能需要子类中的特殊或不同功能.
示例
#!/usr/bin/python3class Parent: # define parent class def myMethod(self): print ('Calling parent method')class Child(Parent): # define child class def myMethod(self): print ('Calling child method')c = Child() # instance of childc.myMethod() # child calls overridden method
执行上述代码时,它产生以下结果 :
Calling child method
基本重载方法
下表列出了一些通用功能您可以在自己的类中覆盖 :
Sr.No. | 方法,描述&样品调用 |
---|---|
1 | __ init __(self [,args ...]) 构造函数(带有任何可选参数) 示例调用: obj = className(args) |
2 | __ del __(self ) 析构函数,删除对象 示例致电: del obj |
3 | __ repr __(self ) 可评估字符串表示 示例调用: repr(obj) |
4 | __ str __(self ) 可打印的字符串表示 示例调用: str(obj) |
5 | __ cmp __(self,x) 对象比较 示例调用: cmp(obj,x) |
重载运算符
假设您已经创建了一个Vector类来表示二维向量.使用加号运算符添加它们会发生什么?很可能Python会对你大喊大叫.
但是,您可以在类中定义 __ add __ 方法来执行向量加法,然后加号运算符将表现为per expectation :
示例
#!/usr/bin/python3class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b)v1 = Vector(2,10)v2 = Vector(5,-2)print (v1 + v2)
执行上述代码时,会产生以下结果 :
Vector(7,8)
数据隐藏
对象的属性在类定义之外可能可见也可能不可见.您需要使用双下划线前缀命名属性,然后这些属性将不会被外人直接看到.
示例
#!/usr/bin/python3class JustCounter: __secretCount = 0 def count(self): self.__secretCount += 1 print (self.__secretCount)counter = JustCounter()counter.count()counter.count()print (counter.__secretCount)
执行上述代码时,会产生以下结果 :
12Traceback (most recent call last): File "test.py", line 12, inprint counter.__secretCountAttributeError: JustCounter instance has no attribute '__secretCount'
Python通过内部更改名称来保护这些成员包括类名.您可以访问 object._className__attrName 等属性.如果您将以下内容替换最后一行,那么它适用于您和减号;
.........................print (counter._JustCounter__secretCount)
执行上述代码时,它会产生以下结果 :
122