Skip to content

Python编码规范

Python 编码规范

参考Google Python语言规范

Lint

使用PyLint TODO 这里贴一下 Sublime Text 3 的 Anaconde 的安装和配置

导入

仅对包和模块使用导入. 不要使用相对名称, 即使模块在同一个包中, 也要使用完整包名. 这能帮助你避免无意间导入一个包两次.

导入格式

  1. 每个导入应该独占一行 这个可以使用PyLint来自动格式化
  2. 导入应该按照从最通用到最不通用的顺序分组:
    • 标准库导入
    • 第三方库导入
    • 应用程序指定导入
  3. 每种分组中, 应该根据每个模块的完整包路径按字典序排序, 忽略大小写.

异常

  1. 像这样触发异常: raise MyException("Error message") 或者 raise MyException. 不要使用两个参数的形式( raise MyException, "Error message" )或者过时的字符串异常( raise "Error message" ).
  2. 永远不要使用 except: 语句来捕获所有异常, 这样会捕获包括Python语法错误在内的任何错误. 使用 except: 很容易隐藏真正的bug.
  3. 当捕获异常时, 使用 as 而不要用逗号: except Error as error

全局变量

避免使用全局变量, 除了一些常量和缓存,常量名应全大写, 用下划线连接

列表推导

在简单情况下使用,禁止多重for或者过滤器表达式,例如: result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]

默认迭代器和操作符

在使用容器类型,例如字典, 列表及文件等时, 使用默认的迭代器和操作符 应该使用 for key in adict:... if key not in adict:... if obj in alist:... for line in afile:... for k, v in dict.iteritems():... 而不是 for key in adict.keys():... if not adict.has_key(key):... for line in afile.readlines():...

生成器

鼓励使用,简化代码, 因为每次调用时, 局部变量和控制流的状态都会被保存. 比起一次创建一系列值的函数, 生成器使用的内存更少.

Lambda

  1. 比本地函数更难读和调试,适用于单行函数, 如果代码太长,还是最好定义成常规的函数.
  2. 对于常见的操作符, 例如乘法操作符, 使用operator模块中的函数代替lambda, 这样代码更简洁,也更快. 推荐使用operator.mul, 而不是lambda x, y: x * y

条件表达式

适用于单行函数, 在其他情况下,推荐使用完整的if语句

默认参数值

可以使用,但不要使用可变对象例如列表或字典之类作为默认值. 这可能会导致问题. 如果函数修改了对象(例如向列表追加项), 默认值就被修改了.

True/False的求值

尽可能的使用隐式false. 使用Python布尔值的条件语句更易读也更不易犯错,大部分情况下也更快.使用if foo:而不是if foo != []:

  1. 永远不要用==或者!=来比较单件, 比如None. 使用is或者is not.
  2. 永远不要用==将一个布尔量与false相比较. 使用 if not x: 代替. 如果你需要区分falseNone, 你应该用像 if not x and x is not None: 这样的语句.
  3. 对于序列(字符串, 列表, 元组), 要注意空序列是false. 因此 if not seq: 或者 if seq: 比 if len(seq):if not len(seq): 要更好.
  4. 处理整数时, 使用隐式false可能会得不偿失(即不小心将None当做0来处理). 你可以将一个已知是整型(且不是len()的返回结果)的值与0比较.
  5. 注意'0'(字符串)会被当做true.

过时的语言特性

尽可能使用字符串方法取代字符串模块. 使用函数调用语法取代apply(). 使用列表推导, for循环取代filter(), map()以及reduce().

线程

不要依赖内建类型的原子性. 虽然Python的内建类型例如字典看上去拥有原子操作, 但是在某些情形下它们仍然不是原子的(即: 如果hasheq被实现为Python方法)且它们的原子性是靠不住的. 你也不能指望原子变量赋值(因为这个反过来依赖字典).

优先使用Queue模块的 Queue 数据类型作为线程间的数据通信方式. 另外, 使用threading模块及其锁原语(locking primitives). 了解条件变量的合适使用方式, 这样你就可以使用 threading.Condition 来取代低级别的锁了.

行长度

每行不超过80个字符 例外: 1. 长的导入模块语句 2. 注释里的长url

不要使用反斜杠连接行, 过长的语句应该使用圆括号实现隐式行连接,而不是在行中插入\ .

括号

除非是用于实现行连接或在元组两边使用,否则不要在返回语句或条件语句中使用括号.

缩进

用4个空格来缩进代码, 不混用tab和空格. 行连接的情况下,要么垂直对齐换行的元素, 或者使用4空格的悬挂式缩进(这时第一行不应该有参数) 这个可以使用PyLint来自动格式化

空行

顶级定义之间空两行, 比如函数或者类定义. 方法定义, 类定义与第一个方法之间, 都应该空一行. 函数或方法中, 某些地方要是你觉得合适, 就空一行. 这个可以使用PyLint来自动格式化

空格

按照标准的排版规范来使用标点两边的空格 1. 括号内不要有空格. Yes: spam(ham[1], {eggs: 2}, []) No: spam( ham[ 1 ], { eggs: 2 }, [ ] ) 2. 不要在逗号, 分号, 冒号前面加空格, 但应该在它们后面加(除了在行尾) 3. 参数列表, 索引或切片的左括号前不应加空格. Yes: spam(1) Yes: dict['key'] = list[index] No: spam (1) No: dict ['key'] = list [index] 4. 在二元操作符两边都加上一个空格, 比如赋值(=), 比较(==, <, >, !=, <>, <=, >=, in, not in, is, is not). 5. 当’=’用于指示关键字参数或默认参数值时, 不要在其两侧使用空格 6. 不要用空格来垂直对齐多行间的标记, 因为这会成为维护的负担(适用于:, #, =等):

` Yes:
 foo = 1000  # comment
 long_name = 2  # comment that should not be aligned

 dictionary = {
     "foo": 1,
     "long_name": 2,
    }`

`No:
 foo       = 1000  # comment
 long_name = 2     # comment that should not be aligned

 dictionary = {
     "foo"      : 1,
     "long_name": 2,
     }`

这个可以使用PyLint来自动格式化

Shebang

大部分.py文件不必以#!作为文件的开始. 根据 PEP-394 , 程序的main文件应该以 #!/usr/bin/python2或者 #!/usr/bin/python3开始.

注释

  1. 独立成行的注释可以使用三重双引号"""也可以使用#.
  2. 使用#的时候在#和注释文本间留一个空格.
  3. 行内注释, 为了提高可读性, 注释应该至少离开代码2个空格.

这个可以使用PyLint来自动格式化

如果一个类不继承自其它类, 就显式的从object继承. 嵌套类也一样. 这是为了使属性(properties)正常工作, 并且这样可以保护你的代码, 使其不受Python 3000的一个特殊的潜在不兼容性影响. 这样做也定义了一些特殊的方法, 这些方法实现了对象的默认语义, 包括: __new__, __init__, __delattr__, __getattribute__, __setattr__, __hash__, __repr__, and __str__

字符串

  1. 避免在循环中用+和+=操作符来累加字符串. 由于字符串是不可变的, 这样做会创建不必要的临时对象, 并且导致二次方而不是线性的运行时间. 作为替代方案, 你可以将每个子串加入列表, 然后在循环结束后用 .join 连接列表.
  2. 在同一个文件中, 保持使用字符串引号的一致性. 使用单引号’或者双引号”之一用以引用字符串, 并在同一文件中沿用.

文件和sockets

在文件和sockets结束时, 显式的关闭它.推荐使用 “with”语句 以管理文件.

语句

每个语句应该独占一行. 特别地, 绝不要对 try/except 这样做, 因为try和except不能放在同一行.

命名

应该避免的名称: 1. 单字符名称, 除了计数器和迭代器. 2. 包/模块名中的连字符(-) 3. 双下划线开头并结尾的名称(Python保留, 例如init)

命名约定: 1. 用单下划线(_)开头表示模块变量或函数是protected的(使用import * from时不会包含). 2. 用双下划线(__)开头的实例变量或方法表示类内私有. 3. 将相关的类和顶级函数放在同一个模块里. 不像Java, 没必要限制一个类一个模块. 4. 对类名使用大写字母开头的单词(如CapWords, 即Pascal风格), 但是模块名应该用小写加下划线的方式(如lower_with_under.py). 5. 全局变量应全大写, 用下划线连接

Main

即使是一个打算被用作脚本的文件, 也应该是可导入的. 并且简单的导入不应该导致这个脚本的主功能(main functionality)被执行, 这是一种副作用. 主功能应该放在一个main()函数中.