高效Python的建议 Effective Python
这里是<编写高质量Python代码的59个有效方法>的笔记, 对于其中的59个Tips, 选取了部分, 做了浓缩和精炼, 并在适当的地方做了补充说明.
需要注意的是, 每个人使用python的场景, 习惯和合作伙伴都不同, 因此对于原书中的建议我根据自身情况做了删减和修改, 希望读者在阅读时也不要将这些建议奉为圭臬, 而需要知其所以为而化为自己的习惯.
风格
- 尽可能使用Python3, 逐渐弃用Python2.
- 遵循PEP8风格规范, 这方面几乎所有编辑器都有对应的自动化语法检查工具来帮助你做到这点.
- 为了可读性, 不要写太复杂的单行表达式. 为了所谓的紧凑或者美观或者节省一两行的空间去牺牲可读性是愚蠢而不专业的. 这里尽量使用列表推导来代替
map
和filter
, 并且不要使用嵌套两层及以上的列表推导. - 为了节省内存, 可以使用生成器表达式来改写数据量较大的列表推导. (而且区别仅在于前者是
()
括号, 后者是[]
括号). - 尽量用
enumerate
取代range
. - 不要再
for
和while
后写else
块. (for/while + else
在python中是一个较为少用的特性, 详见这里). 因为这种表达不直观而容易造成误解.
函数
- 用异常来表示特殊情况,不要返回
None
- 注意闭包中的变量作用域 (关于闭包可以参考这里)
- 需要用函数产生系列结果时不妨用生成器代替返回列表(更突出产生的内容, 更省内存), 但需要注意生成器返回的迭代器不应被反复调用.
用数量可变的位置参数(如*args)使得函数更清晰.
对重要参数指定其职能以关键词形式传入(
def foo(a, b, *, x=1, y=0)
函数中,*,
后面的一定要以关键词形式指定, 无法以位置参数指定). 这样可以减少调用者混淆参数带来的问题.
类和继承
- 尽量用辅助类来维护程序状态,不要用字典和元组(特别是多层字典或者过长的元组, 对于简单数据可以用
namedtuple
). - 用
@classmethod
形式的多态去通用的构建对象(例如将) - 总是用
super
函数来初始化父类以避免初始化顺序和钻石继承的问题. - 尽量避免多重继承.
- 多用
public
属性, 少用private
属性. (通常滥用private
属性被认为是自私的, 大多数情况下,protected
属性是private
的一种有效代替, 参见这里) - 自定义容器类型时可以继承
collections.abc
以方便开发(提示未实现的接口/免去自己实现一些函数).
属性和元类
- Python中不同需求下的属性建议以不同方式实现, 因需制宜:
属性需求 | 实现 | 示例 | Tips |
---|---|---|---|
简单属性 | 直接使用公开属性 | self.xxx = 0 |
|
在set/get 时需执行特殊行为 |
使用@property |
self._xxx=0 .... <br>@property def xxx(self): $\qquad$ return self._xxx |
@property 还可以用于属性重构 |
需复用特殊行为的多个属性 | 实现描述符 | 实现类的__set__ 和__get__ 方法以遵从描述符协议 |
为了防止泄露内存你可以用weakref 模块 |
没有预先定义好的属性(动态) | 使用__getattr__ 等 |
通过实现以下方法: __getattr__ __getattribute__ __setattr__ |
- 元类(实现了
__new__
的type
类)可以用来检验子类是否符合标准, 也可以注册子类.
内置模块
- 用
functools.wraps
定义函数修饰器来避免help
函数失效等问题. - 用
contextlib
和with
语句来改写可复用的try/finally
代码可以更好的管理上下文. - 使用内置算法和数据结构以提升速度, 双向队列
collections.deque
,有序字典collections.OrderedDict
, 带默认值字典collections.defaultdict
, 堆deapq
, 二分查找bisect
, 以及itertools
中大量迭代器相关工具.
协作开发
- 为每个函数, 类和模块编写文档字符串.
- 谨慎使用
from foo import *
形式的引入语句. - 为自编的模块定义根异常, 以便将调用者和API相隔离.
- 注意循环依赖的问题, 可以通过调整引入顺序,动态引入等方法解决该问题, 但是最好的方法是顶层设计上就避免出现这种依赖.
- 使用虚拟环境隔离项目.
部署
- 实现
__repr__
协议来给出必要的信息以帮助调试. - 用
unittest
测试代码. - 学会使用
pdb
来调试. - 使用
cProfile
模块来分析代码性能以便优化.
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 陆陆自习室!
评论