编写高质量代码 | 沐雨浥尘

编写高质量代码

  • Writing Solid Python Code–91 Suggestions to Improve Your Python Program
  • 《改善Python程序的91个建议》读书笔记
  • Pythonic编程

第1章 引论

  • Sug 1: Pythonic,充分体现Python自身特色的代码风格。
  • Sug 1: 实现快速排序函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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最推荐的字符串格式化方法

    1
    print '{greet} from {language}'.format(greet = 'Hello World', language = 'Python')
  • Sug 2: 避免劣化代码

    • 避免只用大小写来区分不同的对象
    • 避免使用容易引起混淆的名称
    • 不要害怕过长的变量名

总的来说,变量名的命名应更具有实际意义

  • Sug 2: PEP8是一篇关于Python编码风格的指南

    1
    2
    3
    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或者使用跳转表实现

    1
    2
    3
    4
    5
    6
    7
    8
    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: 函数注释实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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: ifelifwhilefor等循环语句尽量不要嵌套过深,最好能控制在3层以内。

  • Sug 6: 函数参数设计应该考虑向下兼容

    1
    2
    3
    def readfile(filename) # 第一个版本
    def readfile(filename, logger) # 第二个版本,不向下兼容
    def readfile(filename, logger = logger.info) # 第二个版本,向下兼容
  • Sug 7: 将常量集中到一个文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # 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用来捕捉用户所定义的约束,而不是用来捕捉程序本身错误的

    1
    assert x == y, 'not equals'
  • Sug 9: 充分利用Lazy evaluation的特性

    • if x and y, x为false时不计算y
    • if x or y, x为true时不计算y
  • Sug 12: 推荐使用isinstance()检查类型,而不是type()

    1
    isinstance('a',(str, unicode))
  • Sug 15: 使用enumerate()获取序列迭代的索引和值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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自动关闭资源

    1
    2
    with open('test.text', 'w') as f:
    f.write('test')
  • Sug 23: 使用else子句简化循环,当循环自然终结时else从句会被执行一次。

  • Sug 24: 异常处理try-except-else-finally

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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: 判断列表是否为空`

    1
    2
    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遇到未闭合的小括号时会自动将多行代码拼接为一行,并把相邻的两个字符串字面量拼接在一起

    1
    2
    3
    4
    >>>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,因为不需要复制原有列表,效率相对较高。

    1
    2
    3
    4
    5
    6
    7
    8
    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%的总运行时间

    1
    2
    3
    4
    5
    6
    7
    # 略
    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)
    常见数据结构基本操作的时间复杂度

Buy me a cup of coffee