part1.编写高质量Python代码的59个有效方法
PS:整理自书籍《Python 编写高质量Python代码的59个有效方法》,仅供学习整理使用
Cha 1 用Pythonic方式来思考
TIP 1 确认自己所用的Python版本
TIP 2 遵循PEP8风格指南
1.使用space来表示缩进,而不要使用tab
2.文件中的函数和类之间应该用两行空格隔开
3.在同一个类中,各方法之间应该用一个空行隔开
4.在使用下标来获取列表元素,调用函数或给关键字参数赋值的时候,不要在两旁添加空格
5.函数变量及属性应该用小写字母来拼写,各单词之间以下划线相连,例如,lowercase_underscore
6.受保护的实例属性,以单个下划线开头,例如,_leading_underscore
7.私有的实例属性,应该以两个下划线开头,例如,__double_leading_underscore
8.类与异常,应该以每个单词首字母均大写的形式来命名,例如,CapitalizedWord
9.模块级别的常量,应该全部采用大写字母来拼写,各个单词之间以下划线相连,例如。ALL_CAPS
10.类中的实例方法,应该吧首个参数命名为self,以表示该对象自身
11.类方法的首个参数,应该命名为cls,以表示该类自身。
12.每行的字符数不应超过79,可用反斜线和小括号进行多行代码的连接
13.对于占据多行的长表达式来说,除了首行之外的其余各行都应该在通常的缩进级别上再加4个空格
14.采用内联形式的否定词,而不要把否定词放在整个表达式的前面
15.不要通过检测长度的办法来判断是否为空值
16.关于模块的引入
TIP 3 了解bytes,str与unicode的区别
TIP 4 用辅助函数来取代复杂的表达式
1.开发者很容易过度运用Python的语法特性,写出特别复杂并且难以理解的单行表达式。
2.把复杂的表达式移入辅助函数之中。
3.使用if、else表达式,比使用or或者and的Boolean操作符写成的表达式更加清晰
TIP 5 了解切割序列的办法
1.不要写多余的代码:当start索引为0,或end索引为序列长度时,应该将其省略
2.切片操作不会计较start与end是否越界
3.对list赋值的时候,如果使用切片操作,就会把原列表中处在相关范围内的值替换成新值,即便长度不同亦可替换。
TIP 6 在单次切片操作内,不要同时指定start、end、和stride
1.既有start ,end又有 stride的切割操作,可能会令人费解。
2.尽量使用stride为正数,且不带start或end索引
3.在同一个切片操作内,不要同时使用start,end和stride,如果确实需要执行,考虑将其拆解为两条赋值语句,其中一条范围切割,另一条做步进切割,或考虑使用内置itertools模块中的islice
TIP 7 用列表推导来取代map和filter
a = [1,2,3,4,5,6,7,8]
square = [x**2 for x in a]
print(square)
1.列表推导要比内置的map和filter函数清晰,因为它无需额外编写lambda表达式
2.列表推导可以跳过输入列表中的某些元素,如果改用map来做就必须辅以filter方能实现
3.字典与集合也支持推导表达式
TIP 8 不要使用含有两个以上表达式的列表推导
eg: matrix = [[1,2,3],[4,5,6],[7,8,9]]
flat = [x for row in matrix for x in row]
squared = [[x**2 for x in row] for row in matrix]
print(flat) # flat = [1,2,3,4,5,6,7,8,9]
print(squared) # squared = [[1,4,9],[16,25,36],[49,64,81]]
条件语句亦可加入至列表推导式
a = [1,2,3,4,5,6,7,8,9,10]
b = [x for x in a if x > 4 if x % 2 == 0]
c = [x for x in a if x > 4 and x % 2 == 0]
此处if 和 and作用一样,b和c的结果等价
1.列表推导支持多级循环,每一级循环也支持多项条件
2.超过两个表达式的列表推导很难理解,应该尽量避免
TIP 9 用生成器表达式来改写数据量较大的列表推导
列表推导的缺点:在推导过程中,对于输入序列的每个值来说,可能都要创建仅含一项元素的全新列表,当数据非常多时,可能会消耗大量内存,导致程序崩溃。
按照列表推导的写法写迭代器,将中括号换成小括号,即可得到迭代器,结合next函数生成所需要的值。
eg: it = (len(x) for x in open('/tmp/my_file.txt'))
print(it)
print(next(it))
1.当输入的数据量较大时,列表推导可能会因为占用太多内存而出问题
2.由生成器表达式所返回的迭代器,可以逐次产生输出值,避免内存用量问题
3.把某个生成器表达式所返回的迭代器,放在另一个生成器表达式的for子表达式中,即可将二者组合起来
4.串在一起的生成器表达式执行速度很快
TIP 10 尽量用enumerate取代range
1.enumerate函数提供了一种精简的写法,可以在遍历迭代器时获知每个元素的索引
2.尽量用enumerate来改写那种将range与下标访问相结合的序列遍历代码
3.可以给enumerate提供第二个参数,以指定开始计数时所用的值(默认为0)
TIP 11 用ZIP函数同时遍历两个迭代器
1.内置的zip函数可以平行地遍历多个迭代器
2.Python3的zip相当于生成器,会在遍历过程中逐次产生元祖,而Python2中的zip则是直接把这些元祖完全生成好,并一次性返回整份列表。
3.如果提供的迭代器长度不等,那么zip就会自动提前终止
4.itertools内置模块中的zip_longest函数可以平行遍历多个迭代器,而不用在乎它们的长度是否相等。
TIP 12 不要在for和while循环后面写else块
1.Python有种特殊语法,可在for及while循环的内部语句块之后紧跟一个else块
2.只有当整个循环主体都没遇到break语句时,循环后面的else块才会执行
3.不要在循环后面使用else块,因为这种写法既不直观又容易引起误解
TIP 13 合理利用try/except/else/finally结构中的每个代码块
try/finally结构,确保程序能够可靠地关闭文件句柄。
handle = open('/tmp/random_data.txt')
try:
data = handle.read()
finally:
handle.close()
1.无论try块是否发生异常,都可以利用try/finally复合语句中的finally块来执行清理工作
2.else块可以用来缩减try块中的代码量,并把没有发生异常时所要执行的语句与try/except代码块隔开
3.顺利运行try块后,若想使某些操作能在finally块的清理代码之前执行,则可将这些操作写到else块中。