Skip to content

目录

第一章: 培养 Pythonic 思维

Abstract

Pythonic 风格的代码,是开发者在使用 Python 语言编程并相互协作的过程中逐渐形成的。本章讲解如何采用这样的风格编写常见的Python代码。

  • 1 查询自己使用的 Python 版本 
  • 2 遵循 PEP 8 风格指南 
  • 3 了解 bytesstr 的区别 
  • 4 用支持插值的 f-string 取代 C 风格的格式字符串与 str.format 方法 
  • 5 用辅助函数取代复杂的表达式 
  • 6 把数据结构直接拆分到多个变量里,不要专门通过下标访问 
  • 7 尽量用 enumerate 取代 range
  • 8 用 zip 函数同时遍历两个迭代器 
  • 9 不要在 forwhile 循环后面写 else
  • 10 用赋值表达式减少重复代码 

第二章: 列表与字典

Abstract

在Python语言中处理信息时,最常用的方法是把一系列数值保存到列表(list)中。另外一种跟它互补的结构,是字典(dict),字典可以把它存储的查找键(key)映射到对应的值(value)上。本章讲解如何采用这些数据结构来编写程序。

  • 11 学会对序列做切片 
  • 12 不要在切片里同时指定起止下标与步进 
  • 13 通过带星号的 unpacking 操作来捕获多个元素,不要用切片 
  • 14 用 sort 方法的 key 参数来表示复杂的排序逻辑 
  • 15 不要过分依赖给字典添加目时所用的顺序 
  • 16 用 get 处理键不在字典中的情况,不要使用 inKeyError
  • 17 用 defaultdict 处理内部状态中缺失的元素,而不要用 setdefault
  • 18 学会利用 __missing__ 构造依赖键的默认值 

第三章: 函数

Abstract

Python中的函数具备多种特性,这有助于简化编程工作。Python函数的某些性质与其他编程语言中函数的类似,但也有很多是Python独有的。本章介绍如何使用函数来表达开发者的意图,如何让代码更容易复用,以及如何减少bug。

  • 19 不要把函数返回的多个数值拆分到三个以上的变量中 
  • 20 遇到意外状况时应该抛出异常,不要返回 None
  • 21 了解如何在闭包里面使用外围作用域中的变量 
  • 22 用数量可变的位置参数给函数设计清晰的参数列表 
  • 23 用关键字参数来表示可选的行为 
  • 24 用 Nonedocstring 来描述默认值会变的参数 
  • 25 用只能以关键字指定和只能按位置传入的参数来设计清晰的参数列表 
  • 26 用 functools.wraps 定义函数修饰器 

第四章 推导与生成

Abstract

Python有一种特殊的语法,可以迅速迭代列表(list)、字典(dict)与集合(set),并据此生成相应的数据结构,这也使得在函数返回的这种结构上,逐个访问根据原结构所派生出来的一系列值。本章讲解怎样利用这种机制来提升程序效率并降低内存用量,同时提高代码可读性。

  • 27 用列表推导取代 mapfilter
  • 28 控制推导逻辑的子表达式不要超过两个 
  • 29 用赋值表达式消除推导中的重复代码 
  • 30 不要让函数直接返回列表,应该让它逐个生成列表里的值
  • 31 谨慎地迭代函数所收到的参数 
  • 32 考虑用生成器表达式改写数据量较大的列表推导 
  • 33 通过 yield from 把多个生成器连起来用 
  • 34 不要用 send 给生成器注入数据 
  • 35 不要通过 throw 变换生成器的状态 
  • 36 考虑用 itertools 拼装迭代器与生成器 

第五章 类与接口

Abstract

Python是面向对象的语言。用Python编程时,经常要编写新的类,而且还要定义这些类应该如何通过其接口以及继承体系与其他代码相交互。本章讲解怎样使用类来表达对象所应具备的行为。

  • 37 用组合起来的类来实现多层结构,不要用嵌套的内置类型 
  • 38 让简单的接口接受函数,而不是类的实例 
  • 39 通过 @classmethod 多态来构造同一体系中的各类对象 
  • 40 通过 super 初始化超类 
  • 41 考虑用 mix-in 类来表示可组合的功能 
  • 42 优先考虑用 public 属性表示应受保护的数据,不要用 private 属性表示 
  • 43 自定义的容器类型应该从 collections.abc 继承 

第六章 元类与属性

Abstract

元类(metaclass)与动态属性(dynamic attribute)都是很强大的Python特性,但它们也有可能会让程序出现古怪的行为与意外的效果。本章讲解这些机制的习惯用法,确保最终写出来的代码遵循最小惊讶原则(rule of least surprise)。

  • 44 用纯属性与修饰器取代旧式的 settergetter 方法 
  • 45 考虑用 @property 实现新的属性访问逻辑,不要急着重构原有的代码 
  • 46 用描述符来改写需要复用的 @property 方法 
  • 47 针对惰性属性使用 __getattr____getattribute____setattr__ 
  • 48 用 __init_subclass__ 验证子类写得是否正确 
  • 49 用 __init_subclass__ 记录现有的子类 
  • 50 用 __set_name__ 给类属性加注解 
  • 51 优先考虑通过类修饰器来提供可组合的扩充功能,不要使用元类 

第七章 并发与并行

Abstract

用Python很容易写并发程序,这种程序可以在同一时刻做许多件不同的事情。Python也可以通过系统调用、子进程以及C语言扩展来实现并行处理。本章介绍在这些不同情况下,如何充分利用 Python 的相关特性。

  • 52 用 subprocess 管理子进程 
  • 53 可以用线程执行阻塞式 I/O,但不要用它做并行计算 
  • 54 利用 Lock 防止多个线程争用同一份数据 
  • 55 用 Queue 来协调各线程之间的工作进度 
  • 56 学会判断什么场合必须做并发 
  • 57 不要在每次 fan-out 时都新建一批 Thread 实例 
  • 58 学会正确地重构代码,以便用 Queue 做并发 
  • 59 如果必须用线程做并发,那就考虑通过 ThreadPoolExecutor 实现 
  • 60 用协程实现高并发的 I/O 
  • 61 学会用 asyncio 改写那些通过线程实现的 I/O 
  • 62 结合线程与协程,将代码顺利迁移到 asyncio
  • 63 让 asyncio 的事件循环保持畅通,以便进一步提升程序的响应能力 
  • 64 考虑用 concurrent.futures 实现真正的并行计算 

第八章 稳定与性能

Abstract

Python内置了一些功能与模块,可以让程序变得更加可靠。另外,Python还提供了一些工具,可以让我们轻松地提升程序的性能。本章讲解怎样用Python优化程序,让这些程序在正式的运行环境中表现得更加稳定、更加高效。

  • 65 合理利用 try/except/else/finally 结构中的每个代码块 
  • 66 考虑用 contextlibwith 语句来改写可复用的 try/finally代码
  • 67 用 datetime 模块处理本地时间,不要用 time 模块 
  • 68 用 copyreg 实现可靠的 pickle 操作 
  • 69 在需要准确计算的场合,用 decimal 表示相应的数值 
  • 70 先分析性能,然后再优化 
  • 71 优先考虑用 deque 实现生产者-消费者队列 
  • 72 考虑用 bisect 搜索已排序的序列 
  • 73 学会使用 heapq 制作优先级队列 
  • 74 考虑用 memoryviewbytearray 来实现无须拷贝的 bytes 操作 

第九章 测试与调试

Abstract

不管使用哪种语言编程,都应该把写出来的代码测试一下。但对于Python来说,还有个特殊的问题,那就是它所提供的动态机制可能会增加程序在运行时出现错误的风险。好在Python也让我们可以比较容易地编写测试代码和故障诊断程序。本章讲解怎样用Python内置的工具来测试并调试程序。

  • 75 通过 repr 字符串输出调试信息 
  • 76 在 TestCase 子类里验证相关的行为 
  • 77 把测试前、后的准备与清理逻辑写在 setUptearDownsetUpModuletearDownModule 中,以防用例之间互相干扰 
  • 78 用 Mock 来模拟受测代码所依赖的复杂函数 
  • 79 把受测代码所依赖的系统封装起来,以便于模拟和测试 
  • 80 考虑用 pdb 做交互调试 
  • 81 用 tracemalloc 来掌握内存的使用与泄漏情况 

第十章 协作开发

Abstract

如果许多人要协作开发Python程序,那就得仔细商量代码的写法了。即便只是个人独立开发,也需要了解如何使用其他人所写的模块。本章介绍标准的工具以及业界总结出来的最佳方法,来说明怎样协作开发Python程序。

  • 82 学会寻找由其他 Python 开发者所构建的模块 
  • 83 用虚拟环境隔离项目,并重建依赖关系 
  • 84 每一个函数、类与模块都要写 docstring
  • 85 用包来安排模块,以提供稳固的 API 
  • 86 考虑用模块级别的代码配置不同的部署环境 
  • 87 为自编的模块定义根异常,让调用者能够专门处理与此 API 有关的异常 
  • 88 用适当的方式打破循环依赖关系 
  • 89 重构时考虑通过 warnings 提醒开发者 API 已经发生变化 
  • 90 考虑通过 typing 做静态分析,以消除 bug 

拓展阅读