编写python高质量python代码的59个有效方法
第1条:确认自己的python版本
第2条:遵循PEP8的风格
1.空格
- 对于 占据多行的长表达式来说, 除了首行之外的其余各行都应该在通常的缩进级别上再加4个空格。
- 每行字符数不应该超过79。
2.命名
- 受保护的实例属性命名, 应该以单个下划线开头, 例如:_leading_underscore。
- 私有属性的命名, 应该以双下划线开头,例如: __leading_underscore。
- 模块级别的常量,应该全部采用大写字母来拼写,各单词之间以下划线相连,例如:ALL_CAPS。
3.表达式和语句
- 采用内联形式的否定词,而不是要把否定词放在整个表达式的前面,例如,应该写if a is not b 而不是 if not a is b。
- 不要通过检测长度的办法(如 if len(somelist) == 0) 来判断 somelist 是否为 [] 或 " 等空值, 而是应该采用 if not somelist 这种写法来判断, 它会假定:空值将自动评估为False。
- 检测 somelist 是否为[1]或'hi'等非空值时,也应该如此,if somelist 语句默认会把非空的值判断为True。
- 不要编写单行的 if 语句、for 循环、while 循环及 except 复合语句,而是应该把这些语句分成多行来书写,以示清晰。
- import 语句应该总是放在文件开头。
- 引入模块的时候,总是应该使用绝对名称,而不应该根据当前模块的路径来使用相对名称。例如,引入bar包中的foo模块时,应该完整地写出from bar import foo,而不应该简写为import foo。
- 如果一定要以相对名称来编写import语句,那就采用明确的写法:from.import foo。
- 文件中那些import语句应该按顺序划分为三个部分,分别表示标准库模块、第三方模块以及自用模块。在每一部分之中,各import语句应该按模块的字母顺序来排列
第3条:了解bytes、str与unicode的区别
1.python3中解码和转码方法的使用:
# bytes解码为str def to_str(bytes_to_str): if isinstance(bytes_to_str, bytes): value = bytes_to_str.decode('utf-8') else: value = bytes_to_str return value # str转码为bytes def to_bytes(str_to_bytes): if isinstance(str_to_bytes, str): value = str_to_bytes.encode() else: value = str_to_bytes return value print(to_str(b'/34ea/2323/udfe')) print(to_bytes('dkfjdkj'))
2.从二进制读取或写入二进制文件时,应该总是以'rb'或者'wb'的方式来操作文件
第4条:用辅助函数来取代复杂的表达式(用if/else最简写的方式来取代or和and等)
第5条: 切片的操作细节
1. 不要写多余的代码,当start的索引为0时,end的索引为序列的长度时,可以将其省略
2. start和end的索引可以越界, 例如:列表a长度为10 a[:20] , a[-20:]照样会运行得到所需要的值
3.赋值表达式的左边是一个列表的拷贝,而右边是一个新列表时,则新列表将会覆盖拷贝的列表。例如:a[:] = [101, 23, 34]
第6条: 在单次切片操作内,不要同时指定start、end和stride
1.尽量少使用start、end和stride共同存在的切片
2.如果非要使用,则start和end为空,stride为整数。尽量避免用负数做stride
3.根据上面两点,如果完成比较复杂的切片,可以先做步进切割,然后范围切割,或者先做范围切割,然后进步切割。
4.根据第三点,如果要求不影响程序速度,使用内置itertools模块中的islice
第7条: 用推导式代替map和filter函数
第8条: 不要使用有含有两个以上表达式的列表推导
1.超过两个表达式的列表推导是很难理解的,应该尽量避免
第9条: 用生成器表达式来改写数据量较大的列表推导
1.当输入的数据量较大时,列表推导可能会因为占用太多内存而出现问题
2.由生成器表达式所返回的迭代器,可以逐次产生输出值,从而避免了内存用量问题
3.把某个生成器表达式所返回的迭代器,放在另一个生成器表达式的for子表达式中,即可将二者组合起来
4.串在一起的生成器表达式执行速度很快
1 # 列表推导 2 length = [len(x) for x in open('C:\\Users\\凌汪洪\\Desktop\\sql.txt', 'r')] 3 print(length) 4 5 # 当数据很多的时候,用生成器表达式 6 length = (len(x) for x in open('C:\\Users\\凌汪洪\\Desktop\\sql.txt', 'r')) 7 print(list(length))
第10条: 尽量用enumerate取代range
1.enumerate函数提供了一种精简的写法,可以在遍历迭代器时获知每个元素的索引
2.可以给enumerate提供第二个参数,以指定开始计数时使用的值(默认为0)
第11条: 用zip函数同时遍历两个迭代器
1.内置的zip函数可以平行地遍历多个迭代器
2.如果提供的迭代器长度不等,那个zip就会自动提前终止
3.itertools内置模块中的zip_longest函数可以平行地遍历多个迭代器,而不用在乎他们的长度是否相等
第12条: 不要在for和while循环后面写else块
1.因为这种写法既不直观,又容易引人误解
第13条: 合理利用try/except/else/finally结构中的每个代码块
1.无论try块中的代码是否异常,都可以利用try/finally复合语句中的finally来做清理操作
2.else块可以用来缩减try块中代码量,并把没有发生异常时所要执行的语句与try/except代码块隔开
第14条: 尽量用异常来表示特殊情况,而不要返回None
1 def divice(a, b): 2 try: 3 return a / b 4 except ZeroDivisionError as e: 5 raise ValueError('输入了无意义的数字') from e 6 7 8 x, y = 12, 0 9 try: 10 result = divice(x, y) 11 except ValueError: 12 print("输入了无意义的数字") 13 else: 14 print('result: %d' % result)
第15条: 了解如何在闭包里使用外围作用域中的变量
1.除了那种比较简单的函数,尽量不用nonlocal(而是封装成一个类)
1 def sort_priority(values, group): 2 found = False 3 def helper(x): 4 if x in group: 5 nonlocal found 6 found = True 7 return (0, x) 8 return (1, x) 9 10 # 这里是根据元组的大小进行比较的 11 values.sort(key=helper) 12 return found 13 14 15 numbers = [8, 3, 1, 2, 5, 4, 7, 6] 16 group = {2, 3, 5, 7} 17 sort_priority(numbers, group) 18 print(numbers)
1 # 尽量不用nonlocal
numbers = [8, 3, 1, 2, 5, 4, 7, 6] 2 group = {2, 3, 5, 7} 3 class SortPriority: 4 def __init__(self, group): 5 self.group = group 6 self.found = False 7 8 def __call__(self, x): 9 if x in group: 10 self.found = True 11 return (0, x) 12 return (1, x) 13 14 15 sort_priority = SortPriority(group) 16 numbers.sort(key=sort_priority) 17 print(numbers)
第16条: 考虑用生成器来改写直接返回列表的函数
1 # 普通函数的用法 2 def index_text(text): 3 result = [] 4 if text: 5 result.append(0) 6 for index, letter in enumerate(text): 7 if letter == ' ': 8 result.append(index + 1) 9 return result 10 11 text = 'Four years old' 12 index = index_text(text) 13 print(index) 14 15 16 # 普通函数转换为生成器函数 17 def index_text(text): 18 if text: 19 yield 0 20 for index, letter in enumerate(text): 21 if letter == ' ': 22 yield index + 1 23 24 25 text = 'Four years old' 26 index = list(index_text(text)) 27 print(index)