Skip to content

Python 类与实例 ​

把状态与操作放在一起 ​

类定义一类对象的行为,实例保存各自状态。只有需要把相关状态与操作组合时才引入类;单纯计算通常函数即可。

python
class Notebook:
    category = "notes"  # 类属性,默认由各实例共享读取

    def __init__(self, owner):
        self.owner = owner
        self.pages = []  # 每次构造都得到自己的列表

    def add(self, text):
        self.pages.append(text)

    @classmethod
    def from_owner(cls, owner):
        return cls(owner)

    @staticmethod
    def valid_text(text):
        return bool(text.strip())


a = Notebook("Alice")
b = Notebook.from_owner("Bob")
a.add("first")
assert a.pages == ["first"]
assert b.pages == []
assert Notebook.valid_text("hello")

如果把 pages = [] 写在类体中,多个实例会共享同一个列表,除非显式覆盖。这是类属性和实例属性最容易混淆的地方。Python 属性也可从外部访问,self.owner 并不天然私有。

方法如何选择 ​

写法隐式传入适用情况
实例方法实例 self读写实例状态
@classmethod类 cls替代构造方式、需要感知子类的类级操作
@staticmethod无与类相关,但不需要实例或类;也可以考虑模块函数

__init__ 初始化已创建的实例。继承可以重用并覆盖行为;调用父类实现用 super()。不要仅为了共享几行代码就建立复杂继承层级。

用类组织标准库测试 ​

学会类与实例后,可以将独立测试组织为 unittest.TestCase 的子类。测试方法以 test_ 开头,assertEqual 用于检查实际值与预期值;测试运行器会发现并运行这些方法。

python
# test_total.py
import unittest


class TotalTest(unittest.TestCase):
    def test_sum(self):
        self.assertEqual(sum([1, 2, 3]), 6)
shell
python -m unittest test_total

先按 开发环境选择解释器,再运行上面的命令。示例使用标准库,不需要安装第三方测试工具。

练习与资料 ​

为 Notebook.add 增加空文本检查,用两个实例验证修改互不影响。再比较把 pages 放在类体与 __init__ 中的行为。参见 类教程。下一步读 标准库。

参考解答 ​

将Notebook中add方法替换为以下实现即可,其他方法保留;空白文本明确按ValueError拒绝:

python
def add(self, text):
    if not self.valid_text(text):
        raise ValueError("text must not be blank")
    self.pages.append(text)

提示:先验证再append。两个新实例中只给a添加一条时,b.pages应仍为空;给a传入空白应抛ValueError且a.pages不变。若把pages放进类体且实例没有同名属性,a和b会看到同一列表;这可用 a.pages is b.pages 核对。参考是替换方法片段,未执行。

继续阅读