6.4 KiB
doc_type, full_text
| doc_type | full_text |
|---|---|
| short | sources/01_Class.md |
01_Class 总结
本文介绍 Python 中 class 语句的基本用法,以及如何通过类创建新的对象。核心目标是从元组、字典等松散数据结构,过渡到以对象组织数据与行为的 面向对象编程 风格。
核心概念
面向对象编程
面向对象编程 是一种将程序组织为对象集合的编程技术。对象通常包含两部分:
- 数据:对象的属性(attributes)
- 行为:作用于对象的方法(methods)
例如 Python 列表 nums 是 list 的一个实例:
nums = [1, 2, 3]
nums.append(4)
nums.insert(1, 10)
这里 nums 是对象实例,append() 和 insert() 是绑定到该实例上的方法。
class 语句
class 用于定义一种新的对象类型。例如:
class Player:
def __init__(self, x, y):
self.x = x
self.y = y
self.health = 100
def move(self, dx, dy):
self.x += dx
self.y += dy
def damage(self, pts):
self.health -= pts
类本身只是定义,类似函数定义,单独存在时不会创建对象或执行逻辑。真正被程序操作的是类创建出来的实例。
实例
实例是程序中实际操作的对象,通过“调用类”来创建:
a = Player(2, 3)
b = Player(10, 20)
a 和 b 都是 Player 的实例,但它们是彼此独立的对象。
实例数据
每个实例都有自己的本地数据,通常在 __init__() 中初始化:
class Player:
def __init__(self, x, y):
self.x = x
self.y = y
self.health = 100
保存到 self 上的值就是实例属性,例如 self.x、self.y、self.health。不同实例的属性互不影响:
a.x # 2
b.x # 10
Python 对实例属性的数量和类型没有固定限制。
实例方法
实例方法是定义在类中的函数,用来操作实例内部的数据:
class Player:
def move(self, dx, dy):
self.x += dx
self.y += dy
调用方法时,对象本身会自动作为第一个参数传入:
a.move(1, 2)
等价于把 a 绑定到方法定义中的 self,把 1 绑定到 dx,把 2 绑定到 dy。self 只是约定名称,但 Python 风格要求使用它来表示当前实例。
类作用域注意事项
类定义不会像某些语言那样自动为方法名创建隐式作用域。在类的方法内部,如果要调用同一个对象上的其他方法,必须通过 self 显式引用:
class Player:
def move(self, dx, dy):
self.x += dx
self.y += dy
def left(self, amt):
move(-amt, 0) # 错误:会查找全局函数 move
self.move(-amt, 0) # 正确:调用当前实例的方法
这一点强调了 Python 中对象操作的显式性:要操作实例,就必须明确写出实例引用。
练习主题
本节练习从前面章节的代码出发,将原本使用元组或字典表示的数据,改写为类实例。
Exercise 4.1:用对象作为数据结构
此前股票持仓可以用元组表示:
s = ('GOOG', 100, 490.10)
也可以用字典表示:
s = {
'name': 'GOOG',
'shares': 100,
'price': 490.10
}
本练习要求创建 stock.py,定义 Stock 类,用实例属性表示一笔股票持仓:
class Stock:
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
创建对象:
a = stock.Stock('GOOG', 100, 490.10)
访问字段时,从字典写法:
s['name']
s['price']
变为对象属性写法:
s.name
s.price
该练习强调:类可以看作创建对象的“工厂”,每次调用类都会创建一个拥有独立数据的新实例。
Exercise 4.2:添加方法
为 Stock 添加 cost() 和 sell() 方法,使对象不仅保存数据,还能封装与数据相关的行为:
s = stock.Stock('GOOG', 100, 490.10)
s.cost() # 49010.0
s.sell(25)
s.shares # 75
s.cost() # 36757.5
这体现了 数据与行为封装:股票对象既知道自己的字段,也知道如何计算成本和处理卖出操作。
Exercise 4.3:创建实例列表
本练习将从 CSV 读取出来的字典列表转换为 Stock 实例列表:
portfolio = [
stock.Stock(d['name'], d['shares'], d['price'])
for d in portdicts
]
然后通过对象方法计算总成本:
sum([s.cost() for s in portfolio])
这展示了如何将外部数据解析结果转换为更结构化的对象模型。
Exercise 4.4:在现有程序中使用类
最后要求修改 report.py 中的 read_portfolio(),使其返回 Stock 实例列表,而不是字典列表。同时调整 report.py 和 pcost.py 中的字段访问方式:
s['shares']
改为:
s.shares
修改后,原有功能应保持一致:
pcost.portfolio_cost('Data/portfolio.csv')
# 44671.15
report.portfolio_report('Data/portfolio.csv', 'Data/prices.csv')
这一练习体现了 代码重构:在不大幅改变外部行为的情况下,替换内部数据表示,使程序结构更清晰。
关键收获
- 类是对象类型的定义,本身不会自动创建实例。
- 实例是由类调用产生的实际对象。
- 保存到
self上的数据是实例数据,每个实例各自独立。 - 实例方法是绑定到对象上的函数,第一个参数始终是对象本身。
- Python 约定使用
self表示当前实例。 - 在方法内部调用同一对象的其他方法时,必须写成
self.method(...)。 - 类可以替代字典或元组,用更清晰的属性访问和方法封装组织数据。
- 将程序从字典数据改为对象数据,是面向对象重构的基础步骤。
相关概念
- 面向对象编程
- 类与实例
- 实例属性
- 实例方法
- self参数
- 数据与行为封装
- 代码重构
- Python数据建模