Python 面向对象编程完全指南:从基础到进阶
Python 从诞生起就是面向对象语言,创建和使用类、对象非常容易。本章助你精通 Python OOP 支持。
若无 OOP 经验,建议先阅读入门教程掌握基本概念。下面简要介绍 OOP 术语:
OOP 术语概览
- 类:定义对象属性的用户原型,包含数据成员(类变量、实例变量)和方法,通过点号访问。
- 类变量:被所有实例共享,定义在类内方法外,使用频率低于实例变量。
- 数据成员:类变量或实例变量,保存与类及对象关联的数据。
- 函数重载:同一函数根据对象或参数类型表现不同行为。
- 实例变量:定义在方法内,仅属于当前实例。
- 继承:派生类获得基类特征。
- 实例:某个类的具体对象,如
Circle类的对象obj是Circle的实例。 - 实例化:创建类的实例。
- 方法:定义在类中的特殊函数。
- 对象:由类定义的唯一数据结构实例,包含数据成员和方法。
- 运算符重载:同一运算符赋予多种功能。
创建类
class 语句创建新类定义,类名紧跟关键字 class 后加冒号:
class ClassName:
'Optional class documentation string'
class_suite
- 类有文档字符串,可通过
ClassName.__doc__访问。 class_suite包含定义类成员、数据属性和函数的所有语句。
示例
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__()是构造器/初始化方法,创建新实例时自动调用。- 其他方法像普通函数一样定义,只是第一个参数必须是
self(Python 自动传入,调用时无需提供)。
创建实例对象
调用类名并传入 __init__ 接受的参数即可创建实例:
emp1 = Employee("Zara", 2000)
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)
emp1 = Employee("Zara", 2000)
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 # 添加属性
emp1.age = 8 # 修改属性
del emp1.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(emp1, 'age')
内置类属性
每个 Python 类都有以下内置属性,可像普通属性一样通过点号访问:
__dict__:类命名空间字典。__doc__:类文档字符串,未定义则为None。__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': , 'empCount': 2, 'displayEmployee': , '__doc__': 'Common base class for all employees', '__init__': }
销毁对象(垃圾回收)
Python 自动删除无用对象(内置类型或类实例)释放内存。垃圾回收器在程序运行期间周期性回收引用计数归零的内存块。
对象引用计数随别名数量变化:赋新名、放入容器(列表、元组、字典)计数增 1;del 删除、引用重赋值、引用超出作用域计数减 1。计数归零时自动回收。
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
输出:
3083401324 3083401324 3083401324
Point destroyed
注:最好在单独文件定义类,主程序用 import 导入。
类继承
通过在新类名后括号列出父类实现继承。子类继承父类属性,可像自有属性一样使用,也可覆盖数据成员和方法。
语法
class SubClassName (ParentClass1[, ParentClass2, ...]):
'Optional class documentation string'
class_suite
示例
#!/usr/bin/python
class Parent:
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):
def __init__(self):
print("Calling child constructor")
def childMethod(self):
print('Calling child method')
c = Child()
c.childMethod()
c.parentMethod()
c.setAttr(200)
c.getAttr()
输出:
Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200
多重继承示例:
class A: ...
class B: ...
class C(A, B): ...
用 issubclass() 或 isinstance() 检查类/实例关系:
issubclass(sub, sup):sub是sup子类返回真。isinstance(obj, Class):obj是Class或其子类实例返回真。
重写方法
子类可随时重写父类方法,以实现特殊功能。
示例
#!/usr/bin/python
class Parent:
def myMethod(self):
print('Calling parent method')
class Child(Parent):
def myMethod(self):
print('Calling child method')
c = Child()
c.myMethod()
输出:
Calling child method
基础重载方法
下表列出可在自定义类中重写的通用功能:
| 序号 | 方法、说明及调用示例 |
|---|---|
| 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 类表示二维向量,直接用 + 相加会报错。定义 __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
print(counter.__secretCount)
AttributeError: JustCounter instance has no attribute '__secretCount'
Python 内部将名称改为包含类名。可通过 object._ClassName__attrName 访问。将最后一行改为:
print(counter._JustCounter__secretCount)
输出:
1
2
2
Python