- 示例工程
- 教程
【免费下载链接】python-mastery
Advanced Python Mastery (course by @dabeaz)
本篇技术指南聚焦 David Beazley 的《Advanced Python Mastery》课程第一部分——Python 复习(Python Review)中的第 5 个练习(Exercise 1.5)。它以定义一个简单的Stock股票对象为核心,完整演示了 Python 类的定义、__init__构造方法、实例属性与方法调用的全过程。读完本文,你将能够在自己的项目里写出第一个可复用的数据模型类,并能在交互式解释器中像课程要求那样熟练地创建对象、读取属性、调用方法,为后续练习中类的进阶用法(如属性校验、继承、描述符等)打下基础。
练习背景与目标
在课程的整体安排中,练习 1.1 到 练习 1.6 属于第一章节 "Python Review" 的六个练习。Exercise 1.5 处于承上启下的位置:
- 前一个练习 Exercise 1.4 教你如何把
pcost.py程序改造成portfolio_cost(filename)函数,并引入try/except异常处理; - 后一个练习 Exercise 1.6 则将
pcost.py与stock.py作为模块导入,讲解import语句与if __name__ == '__main__'的用法; - Exercise 1.5 本身则专注于最简单的对象定义——回顾如何定义一个简单的对象(Review of how to define a simple object)。
本练习将创建新文件stock.py,没有任何已有文件需要修改(Files Created:stock.py)。它是全课程中第一个正式引入"类(class)"的练习,后续第 3 章(Classes and Objects)的练习(如 Exercise 3.1 及 解决方案)会在此基础上不断增加新方法(如sell()方法)与读取 CSV 数据的read_portfolio()函数。
注意:本练习的所有工作均在仓库根目录
python-mastery下进行,仓库中的 Data/ 目录存放课程用到的数据文件(如portfolio.dat、portfolio.csv),Solutions/ 目录则存放每个练习的完整参考实现,例如 Solutions/1_5/stock.py。
(a) 定义一个简单的对象:创建 stock.py 并定义 Stock 类
完整的类定义代码
在python-mastery仓库根目录下新建文件stock.py,并在其中输入以下内容:
class Stock: def __init__(self, name, shares, price): self.name = name self.shares = shares self.price = price def cost(self): return self.shares * self.price这段代码定义了名为Stock的类,包含两个成员:
| 成员 | 类型 | 作用 |
|---|---|---|
__init__(self, name, shares, price) | 构造方法(特殊方法) | 在创建对象时自动调用,把传入的参数保存为实例属性self.name、self.shares、self.price |
cost(self) | 普通方法 | 计算并返回该股票持仓的总成本,即shares * price |
仓库中的参考实现 Solutions/1_5/stock.py 与上述代码完全一致,说明这就是本练习的标准答案。
逐行拆解:__init__构造方法与实例属性
class Stock:关键字class声明一个新的类,类名Stock通常采用驼峰命名法(CapWords);def __init__(self, name, shares, price):是 Python 的构造方法。当执行Stock('GOOG', 100, 490.10)时,Python 会自动调用__init__,并自动把新创建的对象作为第一个参数self传入;self.name = name等三行把外部传入的参数分别绑定到对象自身的属性上。self指代"当前这个实例",通过self.xxx = xxx创建的属性属于实例属性(instance attribute),每个实例各自独立存储一份;def cost(self):定义实例方法,同样以self作为第一个参数,方法内部通过self.shares和self.price读取当前实例的属性并做乘法运算。
为什么先学这个"最简单"的对象?
从课程视角看,Stock类虽然简单,但它完整覆盖了 Python 面向对象编程的三个最基本要素:类定义、构造方法与实例属性、实例方法。你之后在 Exercise 1.6 中会通过from stock import Stock导入它,在 Exercise 3.1 及之后的练习中会为其添加sell()方法、属性校验(@property)等内容——可以说本练习的Stock是贯穿整个课程后续章节的核心模型对象。
交互式实验:创建对象并调用方法与属性
完成stock.py后,在与stock.py相同的目录下启动 Python 解释器(本练习没有__main__代码块,直接运行不会产生输出,因此建议进入交互模式实验),逐条输入以下命令:
>>> s = Stock('GOOG',100,490.10) >>> s.name 'GOOG' >>> s.shares 100 >>> s.price 490.1 >>> s.cost() 49010.0 >>> print('%10s %10d %10.2f' % (s.name, s.shares, s.price)) GOOG 100 490.10 >>> t = Stock('IBM', 50, 91.5) >>> t.cost() 4575.0 >>>实验结果逐条解读
s = Stock('GOOG',100,490.10):调用构造方法创建实例。注意490.10在内部被保存为浮点数490.1,所以后面读取s.price显示为490.1;s.name、s.shares、s.price:直接读取实例属性,无需调用任何方法;s.cost():调用实例方法,cost内部计算100 * 490.10 = 49010.0,返回浮点数;print('%10s %10d %10.2f' % (s.name, s.shares, s.price)):使用老式字符串格式化%操作符,把三个属性分别按宽度 10 的字符串、宽度 10 的整数、保留两位小数的浮点数输出,得到整齐对齐的表格行GOOG 100 490.10。这种格式化风格在后继练习(例如 Exercise 3.1 的print_portfolio表格输出,参见 Solutions/3_1/stock.py)中还会反复出现;t = Stock('IBM', 50, 91.5):创建第二个完全独立的实例,验证实例属性互不影响——t.cost()得到50 * 91.5 = 4575.0。
关键知识点:实例是相互独立的
上述实验中s与t是两个不同的对象,各自拥有一份name、shares、price属性副本。修改s.shares不会影响t.shares。这正是面向对象编程中"类是模板、实例是数据载体"的核心思想,也是后续练习中把多个Stock实例放进一个列表(portfolio)来管理投资组合的基础。
与其他练习的衔接:stock.py 在课程中的延伸
Exercise 1.5 的stock.py并非孤立存在,它在课程中会被反复复用:
- 作为模块导入:下一个练习 Exercise 1.6 要求用
from stock import Stock导入该类并创建对象:>>> from stock import Stock >>> s = Stock('GOOG', 100, 490.10) >>> s.name 'GOOG' >>> s.cost() 49010.0由此可见本练习创建的类定义方式必须保证模块可导入、类可实例化,这为第 1.6 节的 import 机制练习提供了素材;
- 类的持续演化:到了第 3 章,Solutions/3_1/stock.py 在原有
Stock类上新增了sell(self, nshares)方法(减少持仓)以及read_portfolio()/print_portfolio()两个模块级函数,后者直接从 CSV 文件(如 Data/portfolio.csv)读取数据并构造Stock实例列表——这一模式正是Stock类从"简单对象"走向"真实数据模型"的演变路径; - 数据文件的对应关系:本练习虽未要求读取数据文件,但课程配套的 Data/portfolio.dat 中的每一行(如
AA 100 32.20)本质上都可以被建模为一个Stock('AA', 100, 32.20)实例,这也是第 3 章练习用 CSV 文件构造 portfolio 列表时的数据来源。
常见问题与调试提示
- 运行
python3 stock.py没有任何输出?这是正常现象——本练习的stock.py只定义了类而没有调用代码,运行它不会产生任何输出。请务必进入交互式解释器(python3 -i或直接执行python3)来创建对象并实验; NameError: name 'Stock' is not defined:说明你还没有执行类的定义代码,或者你在启动解释器后没有先输入class Stock:的完整定义。请确认输入位置与stock.py文件在同一目录;- 交互式实验环境提示:如 Exercise 1.4 所述,本课程后续有大量"定义函数/类后在交互解释器中实验"的场景,可以使用
python3 -i stock.py让解释器运行完文件后停留在交互模式,方便继续实验; - 方法调用后忘记写括号:如输入
s.cost而不带(),Python 不会报错,但会返回方法对象本身(如<bound method Stock.cost of ...>),而不是计算结果——调用方法必须带上括号。
小结与下一步
Exercise 1.5 用最短的代码完成了课程中"对象与类"的第一次落地:通过class Stock定义类,通过__init__保存实例属性,通过cost()提供行为,并在交互式环境中验证了多实例的独立性。掌握本练习后,你已具备在 Python 中定义数据模型类的基本能力。
下一步建议:完成本练习后,请接着完成 Exercise 1.6,学习如何通过import stock/from stock import Stock把stock.py当作模块复用,并掌握if __name__ == '__main__'的模块化编程习惯——那是从"脚本"走向"程序"的关键一步。若在练习中卡住,可以参考仓库中的参考答案(即本练习的标准解法)或直接对照 Solutions/1_5/stock.py 的参考实现。
- 示例工程
- 教程
【免费下载链接】python-mastery
Advanced Python Mastery (course by @dabeaz)
相关推荐
Advanced Python Mastery 练习 6.1 详解:用 Structure 基类简化数据结构定义
Advanced Python Mastery 练习 6.1 详解:用 Structure 基类简化数据结构定义 本篇文章围绕 python mastery 课
示例工程教程如何掌握Python面向对象编程:explore-python类与对象完全教程
如何掌握Python面向对象编程:explore python类与对象完全教程 Python面向对象编程是软件开发中的核心技能,本教程将通过explore py
文档/教程Graphene ObjectType 完全指南:用 Python 类定义 GraphQL 对象类型与 Resolver
Graphene ObjectType 完全指南:用 Python 类定义 GraphQL 对象类型与 Resolver Graphene 是 Python 生
后端API设计
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考