编写高质量代码——改善Python程序的91个建议
Writing Solid Python Code--91 Suggestions to Improve Your Python Program
第1章 引论
- Sug 1: Pythonic,充分体现Python自身特色的代码风格。
Sug 1: 实现快速排序函数:
def quicksort(array): less = [] greater = [] if len(array) <= 1: return array pivot = array.pop() for x in array: if x <= pivot: less.append(x) else: greater.append(x) return quicksort(less) + [pivot] + quicksort(greater)
Sug 1: Pythonic最推荐的字符串格式化方法
print '{greet} from {language}'.format(greet = 'Hello World', language = 'Python')
Sug 2: 避免劣化代码
- 避免只用大小写来区分不同的对象
- 避免使用容易引起混淆的名称
- 不要害怕过长的变量名
总的来说,变量名的命名应更具有实际意义
Sug 2: PEP8是一篇关于Python编码风格的指南
pip install -U pep8 pep8 --first test.py pep8 --show-source --show-pep8 test.py
Sug 3: 三元操作符
?
等价于X if C else Y
Sug 3:
switch...case
语句实现:if...elif...elif...else
或者使用跳转表实现def f(n): return { 0: 'You typed zero.\n', 1: 'You are in top.\n', 2: 'n is an even number.\n' }.get(n, 'Only single-digit number are allowed.\n') # dict.get(key, default=None)
Sug 4: 函数注释实例
def funcName(parameter1, parameter2): """Describe what this function does. Args: parameter1:parameter type, what is this parameter used for. parameter2:parameter type, what is this parameter used for. Returns: return type, return value """ function body
Sug 6:
if
、elif
、while
、for
等循环语句尽量不要嵌套过深,最好能控制在3层以内。Sug 6: 函数参数设计应该考虑向下兼容
def readfile(filename) # 第一个版本 def readfile(filename, logger) # 第二个版本,不向下兼容 def readfile(filename, logger = logger.info) # 第二个版本,向下兼容
Sug 7: 将常量集中到一个文件
# coding:utf-8 # class _const: class ConstError(TypeError): pass class ConstCaseError(ConstError): pass def __setattr__(self, name, value): if name in self.__dict__: raise self.ConstError("can't change const %s" % name) if not name.isupper(): raise self.ConstCaseError('const name "%s" is not all uppercase' % name) self.__dict__[name] = value # # import sys # sys.modules[__name__] = _const() const = _const() const.PI = 3.14 # 在另一个.py文件中引用 from const import const print const.PI
第2章 编程惯用法
Sug 8:
assert
用来捕捉用户所定义的约束,而不是用来捕捉程序本身错误的assert x == y, 'not equals'
Sug 9: 充分利用Lazy evaluation的特性
if x and y
, x为false时不计算yif x or y
, x为true时不计算y
Sug 12: 推荐使用
isinstance()
检查类型,而不是type()
isinstance('a',(str, unicode))
Sug 15: 使用
enumerate()
获取序列迭代的索引和值for i,e in enumerate(list): # 函数原型 def enumerate(sequence, start = 0): n = start for elem in sequence: yield n, elem n += 1 # 反序 def myenumerate(sequence): n = -1 for elem in reversed(sequence): yield len(sequence) + n, elem n = n - 1
Sug 16:
is
表示的是对象标识符,而==
表示的意思是相等。Sug 17:
decode()
将其他编码对应的字符串解码成unicode,而encode()
将unicode编码转换为另一种编码。Sug 17: 源文件编码说明
# coding = utf-8
第3章 基础语法
Sug 19:
import
的使用- 一般情况下尽量优先使用
import a.B
- 有节制地使用
from a import B
- 尽量避免使用
from a import *
- 一般情况下尽量优先使用
Sug 22: 使用
with
自动关闭资源with open('test.text', 'w') as f: f.write('test')
Sug 23: 使用
else
子句简化循环,当循环自然终结时else从句会被执行一次。Sug 24: 异常处理
try-except-else-finally
try: <statements> except <name1>: <statements> # 当try中发生name1的异常时处理 except (name2, name3): <statements> # 当try中发生name2或name3中的某一个异常时处理 except <name4> as <data>: <statements> # 当try中发生name4的异常时处理,并获取对应实例 except: <statements> # 其他异常发生时处理 else: <statements> # 没有异常发生时处理 finally: <statements> # 不管有没有异常发生都会执行
Sug 25: 不推荐在
finally
中使用return语句进行返回- 如果
finally
语句中产生了新的异常或者执行了return
或者break
语句,那么临时保存的异常信息将会被丢失 - 在执行
try
语句块的return
之前,如果finally
语句块中存在return
会直接返回
- 如果
Sug 26: 判断列表是否为空`
if list1: do something
Sug 27: 连接字符串应优先使用
join
而不是+
Sug 28: 格式化字符串转换类型
| 转换类型 | 解释 | |---|---| | c | 转换为单个字符,对于数字将转换该值对应的ASCII码 | | + | 转化为字符串,对于非字符串对象,将默认调用
str()
函数进行转换 | | r | 用repr()
函数进行字符串转换 | | i d | 转换为带符号的十进制数 | | u | 转换为不带符号的十进制数 | | o | 转化为不带符号的八进制数 | | x X | 转化为不带符号的十六进制 | | e E | 表示为科学记数法表示的浮点数 | | f F | 转成浮点数(小数部分自然截断)| | g G | 如果指数大于-4或者小于精度值则和e/E相同,其他情况与f/F相同 |Sug 30: 列表解析
[expr for iter_item in iterable if cond_expr]
Sug 31: 函数传参既不是传值也不是传引用,应该是传对象。根绝对象是否可变进行区分
Sug 33: 慎用变长参数
*args
: 用于接受一个包装为元组形式的参数列表来传递非关键参数**kwags
: 接受字典形式的关键字参数列表
Sug 34:
str()
主要面向用户,其目的是可读性;repr
面向的是python解释器
第4章 库
Sug 36: Python遇到未闭合的小括号时会自动将多行代码拼接为一行,并把相邻的两个字符串字面量拼接在一起
>>>s = ('this is ' 'a long sentence') >>>s 'this is a long sentence'
Sug 36: 判断一个变量s是不是字符串应使用
isinstance(s, basestring)
,basestring是str和unicode的基类Sug 36:
split()
先去除字符串两端的空白字符,然后以任意长度的空白字符串作为界定符分切字符串;而split('')
直接以空格作为界定符Sug 37:
sorted()
函数返回一个排序后的列表,原有列表保持不变;而sort()
函数会直接修改原有列表,函数返回None,因为不需要复制原有列表,效率相对较高。from operator import itemgetter gameresult = [ ['Bob', 95.00, 'A'], ['Alan', 86.00, 'C'], ['Mandy', 82.50, 'A'], ['Rob', 86.00, 'E'] ] sorted(gameresult, key = itemgetter(2, 1)) #output [['Mandy', 82.5, 'A'], ['Bob', 95.0, 'A'], ['Alan', 86.0, 'C'], ['Rob', 86.0, 'E']]
Sug 38: 浅拷贝和深拷贝
- 浅拷贝(shallow copy): 构造一个新的复合对象并将从原对象中发现的引用插入该对象中。
- 深拷贝(deep copy): 构造一个新的复合对象,遇到引用会继续递归拷贝其所指向的具体内容。
Sug 42: 使用pandas处理大型CSV文件
Sug 44 : 序列化,把内存中的数据结构在不丢失其身份和类型信息的情况下转成对象的文本或二进制表示的过程。从效率上,json > pickle > cPickle
第8章 性能剖析与优化
Sug 79: 让正确的程序更快比让快速的程序正确容易得多
Sug 81: 80/20法则,20%的代码的运行时间占用了80%的总运行时间
# 略 if __name__ == '__main__': import cProfile cProfile.run('foo()', 'prof.txt') import pstats p = pstats.Stats('prof.txt') p.sort_stats('time').print_stats()
Sug 83: 时间复杂度比较
- O(1) < O(log* n) < O(n) < O(n log n) < O(n2) < O(cn) < O(n!) < O(nn)