上一章Python教程请查看:python异常处理和断言
自从Python存在以来,Python一直是一种面向对象的语言,但是在Python中创建和使用类和对象非常简单,本章将帮助你成为使用Python的面向对象编程支持的专家。
如果你以前没有任何面向对象(OO)编程的经验,那么你可能需要参考一门介绍性课程,或者至少是某种教程,以便掌握基本概念。
一、OOP术语概述
OOP中常见的术语如下:
- 类-一个用户定义的对象原型,它定义了一组属性来描述类的任何对象。属性是通过点表示法访问的数据成员(类变量和实例变量)和方法。
- 类变量——一个类的所有实例共享的变量。类变量在类中定义,但在类的任何方法之外,类变量的使用频率不如实例变量。
- 数据成员——保存与类及其对象相关的数据的类变量或实例变量。
- 函数重载——指定一个特定函数的多个行为,执行的操作因涉及的对象或参数的类型而异。
- 实例变量——定义在方法内部,只属于类当前实例的变量。
- 继承——把一个类的特性转移到由它派生出来的其他类。
- 一个类的个体对象,例如一个属于类圆的对象obj就是类圆的一个实例。
- 实例化——类实例的创建。
- 方法——类定义中定义的一种特殊函数。
- 对象——由其类定义的数据结构的唯一实例,对象包括数据成员(类变量和实例变量)和方法。
- 操作符重载——将一个以上的函数赋给一个特定的操作符。
二、创建类
类语句创建一个新的类定义,类的名称紧跟在关键字类后面,后面跟一个冒号如下所示:
class ClassName:
'可选类文档字符串'
class_suite
该类有一个文档字符串,可以通过classname .__doc__访问该字符串。
class_suite由定义类成员、数据属性和函数的所有组件语句组成。
下面是一个简单的Python类的例子:
class Employee:
'基类'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print "雇员数 %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
- 变量empCount是一个类变量,它的值在该类的所有实例之间共享,这可以作为雇员访问,类内部或类外部的empCount。
- 第一个方法是一个特殊的方法,称为类构造函数或初始化方法,当你创建该类的新实例时,Python会调用这个方法。
- 除了每个方法的第一个参数是self之外,你可以声明其他类方法,如普通函数。Python将self参数添加到列表中;在调用方法时不需要包含它。
三、创建实例对象
要创建类的实例,你可以使用类名来调用类,并传入类的任意参数。
"这将创建Employee类的第一个对象"
emp1 = Employee("Van Gogh", 2000)
"第二个实例对象"
emp2 = Employee("Oreja", 5000)
四、访问属性
你可以使用带有object的点操作符来访问对象的属性,类变量将使用如下的类名来访问:
emp1.displayEmployee()
emp2.displayEmployee()
print "雇员数: %d" % Employee.empCount
现在把上面所有的概念放在一起:
#!/usr/bin/python
class Employee:
'基类s'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print "雇员数 %d" % Employee.empCount
def displayEmployee(self):
print "Name : ", self.name, ", Salary: ", self.salary
"创建第一个实例对象"
emp1 = Employee("Van Gogh", 2000)
"创建第二个实例对象"
emp2 = Employee("Oreja", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print "雇员数 %d" % Employee.empCount
你可以随时添加、删除或修改类和对象的属性
emp1.age = 7 # 添加'age' 属性.
emp1.age = 8 # 修改'age' 属性.
del emp1.age # 删除 'age' 属性.
你可以使用以下函数,而不是使用常规语句来访问属性:
- getattr(obj, name[, default])——访问对象的属性。
- hasattr(obj,name)——检查属性是否存在。
- 用于设置属性的setattr(obj,name,value),如果属性不存在,那么将创建它。
- delattr(obj, name)删除一个属性。
hasattr(emp1, 'age')
getattr(emp1, 'age')
setattr(emp1, 'age', 8)
delattr(empl, 'age')
五、内置类属性
每个Python类使内置属性后,他们可以使用点操作符访问−像任何其他属性:
(1)__dict__−字典包含类的名称空间。
(2)__doc__−类文档字符串或没有,如果定义。
(3)__name__−类名。
(4)__module__−模块名称的类定义,这个属性是“__main__”互动模式。
(5)__bases__−可能包含基类空元组,按照他们的出现在基类列表中。
上面的类−我们试图访问这些属性
#!/usr/bin/python
class Employee:
'基类'
empCount = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.empCount += 1
def displayCount(self):
print "雇员数 %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__
六、销毁对象(垃圾收集)
Python自动删除不需要的对象(内置类型或类实例)以释放内存空间,Python定期回收不再使用的内存块的过程称为垃圾收集。
Python的垃圾收集器在程序执行期间运行,并在对象的引用计数为0时触发,当指向对象的别名数目改变时,该对象的引用计数也随之改变。
对象的引用计数在分配新名称或放在容器(列表、元组或字典)中时增加,当使用del删除对象、重新分配对象的引用或将其引用移出范围时,对象的引用计数将减少,当对象的引用计数为0时,Python自动收集它。
a = 40 # 创建对象<40>
b = a # <40>增加引用计数
c = [b] # <40>增加引用计数
del a # <40>减少引用计数
b = 100 # <40>减少引用计数
c[0] = -1 # <40>减少引用计数
通常你不会注意到垃圾收集器何时销毁孤立实例并回收其空间,但是类可以实现称为析构函数的特殊方法,该方法在实例即将被销毁时调用,此方法可用于清理实例使用的任何非内存资源。
这个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)
del pt1
del pt2
del pt3
注意理想情况下,应该在单独的文件中定义类,然后使用import语句将它们导入主程序文件。
七、类继承
你可以创建一个类,而不是从零开始,方法是通过在新类名后面的括号中列出父类,从而从一个已存在的类派生该类。
子类继承父类的属性,你可以像在子类中定义属性一样使用这些属性,子类还可以覆盖来自父类的数据成员和方法。
派生类的声明很像它们的父类,但是在类名之后给出了要继承的基类的列表:
class SubClassName (ParentClass1[, ParentClass2, ...]):
'可选类文档字符串'
class_suite
python类继承例子如下:
#!/usr/bin/python
class Parent: # 定义父类
parentAttr = 100
def __init__(self):
print "调用父类构造函数"
def parentMethod(self):
print '调用父类函数'
def setAttr(self, attr):
Parent.parentAttr = attr
def getAttr(self):
print "父类属性 :", Parent.parentAttr
class Child(Parent): # 定义子类
def __init__(self):
print "调用子类构造函数"
def childMethod(self):
print '调用子类函数'
c = Child() # 子类实例
c.childMethod() # 调用子类方法
c.parentMethod() # 调用父类方法
c.setAttr(200)
c.getAttr()
类似地,你可以从多个父类驱动一个类,如下所示
class A: # 定义类A
.....
class B: # 定义类B
.....
class C(A, B): # A和B的子类
你可以使用issubclass()或isinstance()函数来检查两个类和实例之间的关系。
如果给定的子类确实是超类sup的子类,则issubclass(sub, sup)布尔函数返回true。
如果obj是Class类的实例或者是Class子类的实例,则isinstance(obj, Class)布尔函数返回true
八、重写方法
你总是可以覆盖父类方法,重写父方法的一个原因是,你可能希望子类具有特殊或不同的功能。
#!/usr/bin/python
class Parent: # 定义父类
def myMethod(self):
print '调用父类函数'
class Child(Parent): # 定义子类
def myMethod(self):
print '调用子类函数'
c = Child() # 子类实例
c.myMethod()
九、重载基本方法
下表列出了一些可以在自己的类中覆盖的通用功能
编号 | 方法,说明和调用例子 |
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) |
十、重载操作符
假设你创建了一个向量类来表示二维向量,那么当你使用加号操作符将它们相加时会发生什么?
但是你可以在类中定义__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
十一、数据隐藏
对象的属性在类定义之外可能可见,也可能不可见,你需要使用双下划线前缀来命名属性,这样外部人员就不能直接看到这些属性。
#!/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
Python通过内部更改名称以包含类名来保护这些成员,你可以访问object. _classname_attrname等属性,如果你将最后一行替换为以下内容,那么它就适合你:
.........................
print counter._JustCounter__secretCount
评论前必须登录!
注册