前言
书籍阅读笔记
《Python 代码整洁之道:编写优雅的代码》[ 美 ] 苏尼尔·卡皮尔(Sunil Kapil) 著
python代码整洁之道
关于python
命名
使用小写字母命名变量和函数,并用下划线连接单词
类的私有成员(属性/方法):以一个下划线为前缀
防止名称混淆:以两个下划线为前缀
类名:大驼峰方法,即每个单词的首字母大写
常量名:大写字母
类方法:使用 self
作为第一个关键字参数
连接字符串:使用 "".join()
方法(如 "".join([a, b])
)而不是使用内置的字符串连接符(如 a += b
或者 a = a + b
)
在判断是否为 None
时,始终使用 is
或者 is not
(如 if a is not None:
,而非 if a:
)
如果函数有返回值,确保任何执行此函数的地方都返回该值(使用 return None
)
需要检查前缀(字符串的开头部分)和后缀时,考虑 "".startswith()
和 "".endswith()
而不是切片([]
选取)
对两个对象类型进行比较时,考虑 isinstance()
而不是 type()
(如 if isinstance(user_ages, dict):
)
比较 Boolean
值,使用 if is_empty:
当进入 with
代码块时,会调用 __enter__
方法获取资源,并在离开 with
代码块时调用 __exit__
方法释放资源
with connection.NewProtocol(host, port): # connection.py 引用该类
transfer_data()
文档字符串
文档字符串(多行注释:三重引号)是其对象的 __doc__
的特殊属性
def boo(a, b):
"""这是一个加法函数"""
return a+b
boo.__doc__
- 如果在代码中指明了变量类型,就没必要在文档字符串里写参数信息了
- 在文件的顶部放置一个模块级文档字符串来简要描述模块的用法(放在
import
之前) - 使用文档生成工具
控制结构
列表推导:允许在有或没有 if 条件的情况下,在列表中做到以类似于 for
循环的方式解决问题
filtered_data = [item for item in filter if item]
- 与
map
(映射)和filter
(筛选)相比,更具可读性 - 没有复杂条件或复杂计算的情况下使用
使用函数,而不是把 lambda
表达式赋值给一个特定标识符(变量名)
生成器(with open(file_name) as fread:
)和列表推导的主要区别:列表推导将数据保存在内存中
不要在循环后使用 else
- 只有当从循环中正常退出时,
else
子句才会执行(即在循环结束后执行一个额外的操作);使用中断关键字退出循环,则不会
range
不将数据保存在内存中,只存储 start
、stop
、step
值
- 可以对两个
range
数据做比较range(4) == range(4)
- 可以切片
range(10)[2:]
- 在处理数字时,在循环中尽可能多地使用迭代器(
for item in range(10):
)
引发异常
异常帮助 API 或库的使用者了解在函数执行期间失败的原因
在发现当前代码块有运行失败的可能时,抛出异常,而非返回 None
finally
块中的代码总是会被运行。无论是否引发异常,都可以使用 finally
来确保关闭或释放文件或资源
finally:
myfile.close()
创建自己的异常类(如 class UserNotFoundError(Exception):
)
- 要确保知道异常的范围:为自定义的异常设置一组特定的边界
捕获每一个异常,指明异常的类型(如 except NoneType:
),而非使用 except
处理所有异常
了解一些由第三方库抛出的常见异常
考虑添加日志
except ClientError as e:
logger.error("Received error: %s", e, exc_info=True)
数据结构
集合
类型:set
;形式:{}
需要经常访问数据元素,并且在 O(1) 时间内访问这些项,可以考虑使用集合
集合元素不能重复,不支持索引访问,散列查询速度快(集合是使用散列表实现的),可用作其他数据结构的键
namedtuple
实际上是一个带有数据名称的元组,返回和访问数据时使用
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(10, 20)
p.x # 10
p[1] # 20
p._asdict() # 将命名元组转换为字典
Point._make(point_list) # 将列表转换为命名元组
值在初始化后不可更改,字段名必须是字符串
有多个值需要上下传递时,考虑 namedtuple
;元组不会为 tuple
中的数据提供上下文或名称,而 dict
不具有不可变性
Unicode
使用十六进制数字,为几乎所有字符提供了唯一的标识(代码点,code point)
UTF-8 用 1-4 个字节(8/16/24/32位)来表示一个 Unicode 字符,兼容ASCII
- Python 解释器使用 UTF-8 编码
- 编码:将字符映射到位模式
生成器
用列表存在内存泄漏的风险(列表数据存储在内存中)
使用 yield
关键字来生成数字,可作为迭代器的返回值
def get_prime_numbers(lower, higher):
for possible_prime in range(lower, higher):
if is_prime(possible_prime):
yield possible_prime
yield False
zip
将多个可迭代对象(列表、元组、等长序列)中对应位置的元素打包成元组
list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
combined = list(zip(list1, list2))
# [(1, 'a'), (2, 'b'), (3, 'c')]
内置库
collections:有很有用的数据结构,如 namedtuple
、defaultdict
和 orderddict
re:正则表达式
tempfile:创建一次性临时文件
itertools:排列和组合
subprocess:创建多个进程
pickle:序列化和反序列化 Python 对象
__future__:一个伪模块,支持与当前解释器不兼容的新语言特性