Python - 面向对象
上一页下一页
Python 从出现以来一直是一种面向对象的语言。因此,创建和使用类和对象非常容易。本章帮助你成为使用 Python 面向对象编程支持的专家。
如果您以前没有任何面向对象 (OO) 编程的经验,您可能需要查阅有关它的入门课程或至少某种教程,以便掌握基本概念。
不过,这里是面向对象编程 (OOP) 的小介绍,让您快速上手 -
OOP 术语概述
-
类 − 一个用户定义的对象原型,它定义了一组表征类的任何对象的属性。属性是数据成员(类变量和实例变量)和方法,通过点符号访问。
-
类变量 − 由类的所有实例共享的变量。类变量在类内定义,但在类的任何方法之外。类变量不像实例变量那样频繁使用。
-
数据成员 − 保存与类及其对象相关的数据的类变量或实例变量。
-
函数重载 − 将多个行为分配给特定功能。所执行的操作因所涉及的对象或参数的类型而异。
-
实例变量 − 定义在方法内部的变量,只属于类的当前实例。
-
继承 − 将一个类的特征转移到从它派生的其他类。
-
实例 − 某一类的单个对象。例如,属于类 Circle 的对象 obj 是类 Circle 的一个实例。
-
实例化 − 创建一个类的实例。
-
方法 − 在类定义中定义的一种特殊函数。
-
对象 − 由其类定义的数据结构的唯一实例。一个对象包括数据成员(类变量和实例变量)和方法。
-
运算符重载 − 将多个函数分配给特定运算符。
创建类
类 语句创建一个新的类定义。类名紧跟关键字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 是一个类变量,其值在此类的所有实例之间共享。这可以作为 Employee.empCount 访问 从班内或班外。
-
第一种方法__init__() 是一种特殊的方法,称为类构造函数或Python在创建该类的新实例时调用的初始化方法。
-
您声明其他类方法,如普通函数,但每个方法的第一个参数是 self . Python 添加 self 为您列出清单的论据;调用方法时不需要包含它。
创建实例对象
要创建类的实例,您可以使用类名调用该类并传入其 __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/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 "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: 2000 Name : Manni ,Salary: 5000 Total Employee 2
您可以随时添加、删除或修改类和对象的属性 -
emp1.age = 7 # Add an 'age' attribute. emp1.age = 8 # Modify 'age' attribute. del emp1.age # Delete 'age' attribute.
您可以使用以下函数,而不是使用普通语句来访问属性 -
-
getattr(obj, name[, default]) − 访问对象的属性。
-
hasattr(obj,name) - 检查属性是否存在。
-
setattr(obj,name,value) - 设置属性。如果属性不存在,则创建它。
-
delattr(obj, name) - 删除一个属性。
hasattr(emp1, 'age') # Returns true if 'age' attribute exists getattr(emp1, 'age') # Returns value of 'age' attribute setattr(emp1, 'age', 8) # Set attribute 'age' at 8 delattr(empl, 'age') # Delete attribute 'age'
内置类属性
每个 Python 类都遵循内置属性,并且可以像任何其他属性一样使用点运算符访问它们 -
-
__dict__ − 包含类名称空间的字典。
-
__doc__ - 类文档字符串或无,如果未定义。
-
__name__ − 类名。
-
__module__ − 定义类的模块名称。此属性在交互模式下为“__main__”。
-
__bases__ − 包含基类的可能为空的元组,按照它们在基类列表中出现的顺序。
对于上面的类,让我们尝试访问所有这些属性 -
现场演示#!/usr/bin/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 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 employees Employee.__name__: Employee Employee.__module__: __main__ Employee.__bases__: () Employee.__dict__: {'__module__': '__main__', 'displayCount': <function displayCount at 0xb7c84994>, 'empCount': 2, 'displayEmployee': <function displayEmployee at 0xb7c8441c>, '__doc__': 'Common base class for all employees', '__init__': <function __init__ at 0xb7c846bc>}
销毁对象(垃圾回收)
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/python class 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 = pt1 pt3 = pt1 print id(pt1), id(pt2), id(pt3) # prints the ids of the obejcts del pt1 del pt2 del pt3
执行上述代码时,会产生以下结果 -
3083401324 3083401324 3083401324 Point destroyed
注意 - 理想情况下,你应该在单独的文件中定义你的类,然后你应该使用 import 将它们导入你的主程序文件 声明。
类继承
无需从头开始,您可以通过在新类名后面的括号中列出父类,从预先存在的类派生类来创建类。
子类继承其父类的属性,您可以像在子类中定义这些属性一样使用这些属性。子类也可以覆盖父类的数据成员和方法。
语法
派生类的声明很像它们的父类;但是,在类名之后给出了要继承的基类列表 -
class SubClassName (ParentClass1[, ParentClass2, ...]): 'Optional class documentation string' class_suite
示例
现场演示#!/usr/bin/python class 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 child c.childMethod() # child calls its method c.parentMethod() # calls parent's method c.setAttr(200) # again call parent's method c.getAttr() # again call parent's method
执行上述代码时,会产生以下结果 -
Calling child constructor Calling child method Calling parent method Parent attribute : 200
类似地,您可以从多个父类中驱动一个类,如下所示 -
class A: # define your class A ..... class B: # define your class B ..... class C(A, B): # subclass of A and B .....
您可以使用 issubclass() 或 isinstance() 函数来检查两个类和实例的关系。
-
issubclass(sub, sup) 如果给定子类 sub,则布尔函数返回 true 确实是超类 sup 的子类 .
-
isinstance(obj, Class) 如果 obj 则布尔函数返回 true 是类 Class 的一个实例 或者是Class的子类的一个实例
覆盖方法
您始终可以覆盖您的父类方法。重写父类方法的原因之一是您可能希望子类中有特殊或不同的功能。
示例
现场演示#!/usr/bin/python class 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 child c.myMethod() # child calls overridden method
执行上述代码时,会产生以下结果 -
Calling child method
基础重载方法
下表列出了您可以在自己的类中覆盖的一些通用功能 -
Sr.No. | 方法、描述和示例调用 |
---|---|
1 | __init__ ( self [,args...] ) 构造函数(带有任何可选参数) 示例调用:obj =className(args) |
2 | __del__(自我) 析构函数,删除一个对象 示例调用:del obj |
3 | __repr__(自我) 可评估的字符串表示 示例调用:repr(obj) |
4 | __str__(自我) 可打印的字符串表示 示例调用:str(obj) |
5 | __cmp__ (self, x) 对象比较 示例调用:cmp(obj, x) |
重载运算符
假设您创建了一个 Vector 类来表示二维向量,当您使用加号运算符将它们相加时会发生什么? Python 很可能会对你大喊大叫。
但是,您可以定义 __add__ 类中的方法来执行向量加法,然后加号运算符将按预期运行 -
示例
现场演示#!/usr/bin/python class 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/python class JustCounter: __secretCount = 0 def count(self): self.__secretCount += 1 print self.__secretCount counter = JustCounter() counter.count() counter.count() print counter.__secretCount
执行上述代码时,会产生以下结果 -
1 2 Traceback (most recent call last): File "test.py", line 12, in <module> print counter.__secretCount AttributeError: JustCounter instance has no attribute '__secretCount'
Python 通过在内部更改名称以包含类名来保护这些成员。您可以访问诸如 object._className__attrName 之类的属性 .如果您将最后一行替换如下,那么它对您有用 -
......................... print counter._JustCounter__secretCount
执行上述代码时,会产生以下结果 -
1 2 2
Python