1. 确认自己所用的 Python 版本
- 2to3、six 等工具可用于 Python 2 到 Python 3 的代码适配。
2. 遵循 PEP8 风格指南
PEP8
- 每行字符数不超过 79;
- 函数与类之间用两个空行隔开,同一类中的方法之间用一个空行隔开;
- 使用索引时,不在两边加空格;
- 函数、变量、属性使用小写、下划线;
- 受保护属性用单个下划线开头,私有属性用两个下划线开头;
- 类与异常使用大写、无下划线;
- 模块级别的常量使用全部大写、下划线;
- 不用检测长度的方法(
len)来判断序列是否为空;
- 引入模块时使用绝对名称,而不根据当前模块的路径来使用相对名称。如果一定要用相对名称,则使用
. 表示;
import 语句分为三部分:标准库、第三方与自用模块,部分内按字母顺序排列。
3. 了解 bytes, str, Unicode 的区别
bytes 实例包含原始的 8 位字符值,str 实例包含 Unicode 字符;
- 前者转化为后者需要解码(
decode),后者转化为前者需要编码(encode),结果由编解码方式决定;
- Python 程序中要把编解码操作放在最外围,核心部分应当使用 Unicode 字符类型,不依赖于编码的形式;
bytes 和 str 都可以使用加法(连接)、比较大小、格式化字符串(%),但不同类型不可以:
- 不同类型可以使用 ` == ` 比较,但结果永远为 False;
- 可以在格式化
str 时使用 bytes,但会使用 __repr__ 的结果,不符合预期。
open 函数默认使用 UTF-8 编码格式操作文件,encoding='utf-8',此时必须传入/读取包含 Unicode 字符的 str 实例。要使用二进制形式(bytes)读取/写入,必须采用二进制写入模式 'wb';
- 可以使用
python3 -c 'import locale; print(locale.getpreferredencoding())' 来查看系统默认使用的编码方式。
- 最常见方法是
%,语法来自于 printf。同一变量必须在字符串与格式化元组中各指定一次,在调整打印变量的顺序时比较麻烦,用于格式化的变量元组可能因添加附加操作而变得过长,重复打印变量时也需要重复罗列;
% 操作符也支持使用字典而不是元组来格式化字符串,在字符串中使用类似 %(value).2f 的格式来指定变量名。仍存在格式化表达式过长的问题;
str.format 借助了 format 的结果,可以通过类似 {:<10.2f} 的形式指定格式。{} 的转义符为 { {}}。可以指定位置编号 {0}, {1}。也可以在 str.format 中使用关键字参数,并扩展格式字符串位置的表达式 {menu[oyster]}。不过也存在过长的问题;
- f-string 中的格式字符串与上面相同
{key!r:<10}。其中的格式参数也可动态指定 {number:.{places}f}。更简洁,拆分多行更直观;
- 新的格式字符串句法:
, 表示千位分隔符,^ 表示居中。{name!r} 表示使用 __repr__ 而非 __str__ 来翻译为字符串。
5. 用辅助函数来取代复杂的表达式
- 空字符串、空列表、零值都会评估为
False,因此可以用 or 来指定缺省值;
- 如果表达式比较复杂,那么就需要考虑拆解成小块,避免过度运用特性。
6. 使用元组拆包替代索引
- 元组拆包的应用:排序中值的交换,
for 迭代中的直接拆包。
7. 尽量用 enumerate 取代 range
enumerate(iterable, i) 把各种可迭代对象包装成生成器,每次产出一对值,表示索引和迭代器产出值。
8. 用 zip 函数同时遍历两个迭代器
- 如果迭代器长度不等,则会提前终止(依据较短的);
- 可以使用
itertools.zip_longest 遍历多个不等长迭代器,使用 fillvalue 补充缺省部分。
9. 不要在 for 和 while 循环后面写 else 块
- 循环不通过
break 退出时,才会执行 else 块;
- try/except/else 中的
else 块会在没有异常抛出时执行,为 except 的互补块。
10. 使用赋值表达式来避免重复
- (从 Python 3.8 起)赋值表达式
a := b 读作 a walrus b,值为左侧变量的值;
- 常用于
if、while 等语句的条件判断处,实现 C/C++ 中赋值后判断的功能;
- 可优化嵌套 if-else 语句,合并成
elif 条件。