jk's notes

ch09 类

介绍一些 OOP 的概念.

9.1 创建类的语法

class 类名:
  def __init__(self, 参数列表):
    self.属性 = 值
    
  def 方法名(参数):
    方法体

逻辑上与其他 OOP 语言是一样的.

  • 约定类名使用 Pascal 命名规则.

  • __init__() 就是构造函数.

  • 方法内成员访问使用 self 引用当前实例. 如果需要使用需要用参数传入进来.

self 可以理解为默认的一个具名参数.

构造函数中 该参数必传, 且必然在第一个.

从作者行文中, 没有字段一说.

9.2 使用类

介绍实例化, 方法调用, 属性访问等.

变量 = 类名() ## 实例化, 不同于其他语言, 不需要 new

9.3 继承

介绍了父子类等基本概念.

定义类的语法:

class 子类(父类):
  def __init__(self, 其他参数):
    super().__init__(...)
    其他代码
  • 指定被继承的类, 在类名中用圆括号标识.
  • 子类构造函数中, 调用父类构造函数, 使用 super().__init__(...)
  • 重写父类方法的逻辑与 OC 的逻辑一样, 直接定义同名方法, 子类方法直接覆盖.
  • 然后介绍了将属性定义成另一个实例.

然后模拟实物, 演示了一些用法 (无特别).

9.4 导入类

文件 (模块) 中允许有多个类, 导入方式: 导入单个类, 导入整个模块, 导入多个类, 导入所有成员.

然后给类可以创建别名.

用法与函数导入一样.

9.5 标准库

就是内置库. 问题在于: 有哪些标准库, 都怎么使用.

演示 random 库中 randint() 的用法.

from random import randint
print(randint(1, 6)) ## 生成 [1, 6] 之间的一个随机数 (注意是闭区间)

random 模块中有一个方法 choice, 随机返回一个列表 (元组) 中的一项.

from random import choice

list = [ 11, 22, 33, 44 ]
print(choice(list))

9.6 编程风格说明

类名用驼峰, 务必写文档注释, 空行来分隔代码易于阅读. import 后跟空行.

ch10 文件和异常

10.1 读取文件

读取文件内所有数据 (文本读取)

  • 指定文件路径
  • 读取内容
from pathlib import Path
path = Path('文件路径')
content = path.read_text()

读取文件中如果有多余空格, 使用 rstrip() 等方法修剪两端空格.

然后介绍了相对路径, 绝对路径. 最后文件路径建议使用斜线 (/), 可以在不同系统中识别.

按行读取文件内容. 书中给出的示例是读取字符串后, 用 splitlines() 方法将其按行分割.

lines = path.read_text().splitlines()

使用文件中的内容:

  • 读取文件中的内容, 注意读取的是字符串.
  • 必要时需要将其转换为数字时, 可以使用 int(), float() 等函数.

作者给出了一个 demo, 利用输入生日, 后再使用 in 运算符, 判断生日是否出现在圆周率里面.

10.2 写入文件

利用 Path(路径) 获得 path 后, 调用 write_text() 写入文本.

字符串拼接使用 +, 或 +=.

写入多行数据就是使用 \n 连接多个字符串写入.

jk: 记得似乎与以前的版本方法用的不太一样.

10.3 异常

使用 try-except 结构.

首先异常也是有类型名字的, 例如 10/0 会得到 ZeroDivisionError 异常.

try:
  语句
except 异常名:
  异常处理语句
else:
  没有异常时会执行这里

else 块可选. 似乎在 try 语法块中没有块级作用域的概念.

然后介绍了 FileNotFoundError 异常. 并且演示了在读取文件时指定字符编码:

contents = path.read_text(encoding='utf-8')

然后介绍了一个分析文本的案例:

  • 读取一个小说, 爱丽丝漫游奇境记.
  • 读取全文, 使用 split() 方法, 按空格分隔得到单词.
  • 使用 len() 函数获得单词数.
  • 打印.
  • 其中会校验, 当文件不存在时, 通过异常来显示提示.

然后作者将统计功能封装成函数, 以重复调用.

最后介绍静默失败. 即如果不希望处理异常, 在 except 块中使用 press 即可跳过.

10.4 存储数据

两个函数:

  • json.loads() 逻辑上与 JS 中的 JSON.parse() 一样
  • json.dumps() 逻辑上与 JS 中的 JSON.stringify() 一样

然后使用一个案例, 存储用户输入的信息为 JSON 格式的文件.

然后将其封装为函数来演示.

基本逻辑是, 用 json 进行格式化或转换, 作为一个中间步骤来处理数据与文件中存储的格式转换.

ch11 测试代码

本质就是在进行单元测试. 这里使用 pytest

11.1 使用 pip 安装 pytest

pip 相对于 python, 如 npm 相对于 node. pip 会更新比较快. 这里先更新一下:

python -m pip install --upgrade pip

如果是更新某个包

python -m pip install --upgrade 包名

这段命令分为两个部分:

  • python -m pip 表示让 python 运行 pip 模块
  • install --upgrade xxx 表示更新 xxx

注意, linux 中可能不会默认安装 pip.

下面安装 pytest

python -m pip install --user pytest

表示为当前用户 (--user) 安装 pytest 包.

如果出现问题, 可以去掉 --user 再试试.

image-20240123175510181

image-20240123180021280

11.2 测试函数

即为需要被测试的函数.

然后作者简要说明了单元测试 (unit test), 测试用例 (test case) 的概念.

然后解释了 全覆盖测试用例.

然后解释了可通过的测试, 就是在测试用例中进行断言, 断言通过了即为测试通过.

断言的语法:

assert 目标值 == 被测函数返回值

然后解释了如何运行测试, 要用 pytest 来执行文件.

pytest

约定, 编写测试用例的文件名, 必须以 text_ 开头. 同时测试用例的函数名也必须以 test_ 开头.

image-20240123180321114

如果运行 pttest 提示找不到命令, 可以使用 python -m pytest.

大多是环境变量的问题.

然后演示了未通过的测试

image-20240123181522702

然后作者介绍了, 如果不通过怎么处理; 另外介绍了追加测试用例.

11.3 测试类

下面看看如何对类进行测试.

首先是各种断言 (这个很重要, 重要, 重要).

image-20240123182110426

image-20240123182125089

然后要测试一个类, 就是在测试这个类提供的方法的运行是否复合预期.

11.4 使用夹具 (fixture)

在对类的实例进行测试时, 避免重复创建实例, 可以使用夹具.

针对大量测试案例时, 会更为方便.

夹具的作用是为不同的测试用例创建测试资源.

操作步骤:

  1. 编写函数, 该函数中创建实例并返回.
  2. 导入 pytext 模块, 并在资源函数上使用模块中的 fixture 装饰器.
  3. 在测试用例的函数参数中使用资源函数. 用于资源函数同名的变量名作为参数.
  4. 在测试函数内部直接使用参数作为对应实例.
  5. 运行测试

image-20240123192112228

Last Updated:
Contributors: jk