PEP8 编程风格规范

代码布局 (Code Lay-Out)

1. 缩进 (Indentation)

  • 每个缩进级别 4个 空格
  • 连续行所包装元素
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 同开始分界符(左括号)对齐
    foo = long_function_name(var_one, var_two,
    var_three, var_four)

    # 续行多缩进一级以同其他代码区别
    def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)

    # 悬挂缩进需要多缩进一级
    foo = long_function_name(
    var_one, var_two,
    var_three, var_four)
    • Python隐式续行 垂直对齐于圆括号、方括号和花括号
    • 悬挂缩进 第一行不应该包括参数,并且在续行中 (续行来说,4空格的规则可以不遵守) 需要再缩进一级以便清楚表示
  • 多行结束右圆/方/花括号可以单独一行书写,和上一行的缩进对齐;也可以和多行开始的第一行的第一个字符对齐
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    my_list = [
    1, 2, 3,
    4, 5, 6,
    ]
    result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )
    my_list = [
    1, 2, 3,
    4, 5, 6,
    ]
  • 推荐使用空格来进行缩进。Python 3不允许tab和空格混合使用。

2. 每行最大长度(Maximum Line Length)

  • 所有行都限制在 79 个字符以内
  • 连续大段的文字(比如文档字符串(docstring)或注释),其结构上的限制更少,这些行应该被限制在72个字符长度内。
  • 换行方式是利用Python圆括号、方括号和花括号中的隐式续行。长行可以通过在括号内换行来分成多行。应该最好加上反斜杠来区别续行。

3. 二元运算符之前还是之后换行?

  • Kunth 风格: 尽管在段落中的公式总是在二元运算符之后换行,但显示公式时总是在二元运算符之前换行
  • 如果项目约定,也可以在二元运算符之后换行

4. 空行 (支持control + L 换行符作为空格)

  • 使用 2个 空行来分隔最外层的 函数(function)类(class) 定义
  • 使用 1个 空行来分隔 类中的方法(method) 定义
  • 额外的空行(尽量少) 来分隔一组相关的函数
  • 在函数内使用空行(尽量少) 使代码逻辑更加清晰

5. 源文件编码(Source File Encoding)

  • python 2 使用 ASCII
  • python 3 使用 UTF-8
  • Python标准库中的所有标识符都必须只采用ASCII编码的标识符,在可行的条件下也应当使用英文词

6. 模块引用(Imports)

  • imports 分行写,不应都写在一行

    1
    2
    3
    4
    # 分开写
    import os
    # 被允许的
    from subprocess import Popen, PIPE
  • imports 写在代码文件的开头,位于模块(module)注释文档字符串(docstring)之,模块全局变量(globals)和常量(constants)声明之””.

  • imports 顺序 (不同的 imports 之间用空格隔开)

    1. 标准库 imports
    2. 相关第三方 imports
    3. 本地应用/库的特定 imports
  • 推荐使用绝对(absolute) imports (易读且会报错)

    from mypkg import sibling

  • 显式的相对imports也是一种可以接受的替代方式.特别是当处理复杂的包布局(package layouts)时,采用绝对imports会显得啰嗦.

    from .sibling import example

  • 标准库代码应当一直使用绝对imports,避免复杂的包布局.
    隐式的相对imports应该永不使用,并且Python 3中已经被去掉了.

  • 如果从包含类的模块import的类与本地命名产生冲突,可以直接 import 模块

  • 避免使用通配符进行 imports, 会产生许多不必要的麻烦

7. 模块级的双下划线命名(Module level dunder names)

  • 模块及级下划线命名的变量函数,应该在 文档的多行注释字符串之后

8. 字符串的引用(String Quotes)

  • 当字符串中包含单引号时,采用双引号来表示字符串,可以避免使用反斜杠,代码也更易读
  • 在一个项目中最好字符串都用单引号或者双引号

9. 表达式和语句中的空格(Whitespace In Expressions And Statements)

  • 方括号圆括号花括号之后避免使用空格
  • 逗号分号冒号之前避免使用空格
  • 切片操作时避免使用空格
    • 冒号和二元运算符是一样的,应该在其左右两边保留相同数量的空格;
    • 扩展切片操作中,所有冒号的左右两边空格数都应该相等;
    • 切片操作中的参数被省略时,应该也忽略空格.
  • 调用函数时传递参数list的括号之前避免使用空格
  • 索引和切片操作的左括号之前避免使用空格
  • 赋值(或其他)运算符周围使用多个空格来和其他语句对齐
  • 避免任何行末的空格.
  • 二元运算符的两边都使用一个空格:赋值运算符(=),增量赋值运算符(+=, -= etc.),比较运算符(==, <, >, !=, <>, <=, >=, in, not in, is, is not),布尔运算符(and, or, not).
  • 优先级不同的运算符,则在优先级较低的操作符周围增加空白.(不要用超过1个空格,永远保持二元运算符两侧的空白数量一样.)
  • 使用=符号来表示关键字参数或参数默认值时,不要在其周围使用空格.
  • 函数注解中的:也遵循一般的:加空格的规则,在->两侧各使用一个空格.
  • 在组合使用函数注解和参数默认值时,需要在=两侧各使用一个空格(只有当这个参数既有函数注解,又有默认值的时候).
  • 复合语句(即将多行语句写在一行)一般是不鼓励使用的.
  • 短小的if/for/while中的语句写在一行,多分支的不要使用

10. 何时在末尾加逗号(When to use trailing commas)

  • 定义单元素元组(tuple)时是必需的
    1
    FILES = ('setup.cfg',)
  • 在将来有可能扩展的列表末尾添加冗余的逗号,每一个元素写在单独的一行,并在行尾添加逗号,右括号单独占一行.
    1
    2
    3
    4
    FILES = [
    'setup.cfg',
    'tox.ini',
    ]

11. 注释(Comments)

  • 当代码有改动时,一定要优先更改注释使其保持最新.
  • 注释应该是完整的多个句子.如果注释是一个短语或一个句子,其首字母应该大写,除非开头是一个以小写字母开头的标识符(永远不要更改标识符的大小写).
  • 注释很短,结束的句号可以被忽略.块注释通常由一段或几段完整的句子组成,每个句子都应该以句号结束.
  • 在句尾的句号后再加上2个空格.
  • 尽量用英文写注释
  • 块注释(Block Comments)
    • 一般写在对应代码之前,并且和对应代码有同样的缩进级别.块注释的每一行都应该以#和一个空格开头(除非该文本是在注释内缩进对齐的).
  • 行内注释(Inline Comments)
    • 尽量少用行内注释.
      1
      x = x + 1                 # x自加
    • 行内注释是和代码语句写在一行内的注释.行内注释应该至少和代码语句之间有两个空格的间隔,并且以#和一个空格开始.
  • 文档字符串注释(Documentation Strings)
    • 所有的公共模块,函数,类和方法都应该有文档字符串.对于非公共方法,文档字符串不是必要的,但你应该留有注释说明该方法的功能,该注释应当出现在def的下一行.
    • 多行文档字符串以单行”””结尾,不能有其他字符
    • 对于仅有一行的文档字符串,结尾处的”””应该也写在这一行.

12. 命名约定(Naming Conventions)

  • 首要原则(Overriding Principle)

    • 对于用户可见的公共部分API,其命名应当表达出功能用途而不是其具体的实现细节.
  • 命名风格(Descriptive: Naming Styles)

    • CapitalizedWords (也叫做CapWords或者CamelCase – 因为单词首字母大写看起来很像驼峰).也被称作StudlyCaps.
      注意:当CapWords里包含缩写时,将缩写部分的字母都大写.HTTPServerError比HttpServerError要好.
    • mixedCase (注意:和CapitalizedWords不同在于其首字母小写!)
    • Capitalized_Words_With_Underscores (这种风格超丑!)
    • UPPER_CASE_WITH_UNDERSCORES(带下划线大写)
    • UPPERCASE(大写)
    • lower_case_with_underscores(带下划线小写)
    • lowercase(小写)
    • B (单个大写字母)
    • b (单个小写字母)
    • 特殊形式
      • _single_leading_underscore: 以单个下划线开头是”内部使用”的弱标志。
      • single_trailing_underscore_: 以单个下划线结尾用来避免和Python关键词产生冲突
        1
        class_="xxx"
      • double_leading_underscore: 以双下划线开头的风格命名类属性表示触发命名修饰(在FooBar类中,boo命名会被修饰成_FooBar__boo)
      • double_leading_and_trailing_underscore: 以双下划线开头和结尾的命名风格表示“魔术”对象或属性,存在于用户控制的命名空间(user-controlled namespaces)里
  • 命名约定(Prescriptive: Naming Conventions)

    • 需要避免的命名(Names To Avoid)
      • 字符’l’(L的小写的字母)
      • ’O’(o大写的字母)
      • ’I’(i的大写的字母)
    • ASCII兼容性(ASCII Compatibility)
    • 包和模块命名(Package And Module Names)
      • 模块命名应短小,且为全小写.若下划线能提高可读性,也可以在模块名中使用
      • 包命名也应该短小,且为全小写,但不应使用下划线.
      • 使用C或C++写的扩展模块有相应的Python模块提供更高级的接口时, C/C++模块名以下划线开头(例如,_sociket)
    • 类命名(Class Names)
      • 驼峰(CapWords)的命名约定
    • 类型变量命名(Type variable names)
      • 类型变量名称通常应使用简短的驼峰命名
    • 异常命名(Exception Names)
      • 类命名约定也适用与异常.不同的是,如果异常实际上是抛出错误的话,异常名前应该加上”Error”的前缀.
    • 函数命名(Function Names)
      • 函数命名应该都是小写,必要时使用下划线来提高可读性.
    • 全局变量命名(Global Variable Names)
      • 引用方式设计为from M import *的模块,应该使用all机制来避免import全局变量,或者采用下划线前缀的旧约定来命名全局变量,从而表明这些变量是“模块非公开的”.
    • 函数和方法参数(Function And Method Arguments)
      • 实例方法的第一参数永远都是self.
      • 类方法的第一个参数永远都是cls.
      • 在函数参数名和保留关键字冲突时,相对于使用缩写或拼写简化,使用以下划线结尾的命名一般更好.比如,class_比clss更好.
    • 方法命名和实例变量(Method Names And Instance Variables)
      • 使用函数命名的规则:小写单词,必要时使用下划线分开以提高可读性.
      • 仅对于非公开方法和变量命名在开头使用一个下划线
      • 避免和子类的命名冲突,使用两个下划线开头来触发Python的命名修饰机制.
  • 常量(Constants)

    • 常量通常是在模块级别定义的,使用全部大写并用下划线将单词分开.如:MAX_OVERFLOW和TOTAL .

13. 公开和内部接口(Public And Internal Interfaces)

  • 任何向后兼容性保证仅对公开接口适用
  • 文档化的接口被认为是公开的,除非文档中明确申明了它们是临时的或者内部接口,不保证向后兼容性.所有文档中未提到的接口应该被认为是内部的.
  • 为了更好审视公开接口和内部接口,模块应该在all属性中明确申明公开API是哪些.将all__设为空list表示该模块中没有公开API.

14. 编程建议(Programming Recommendations)

  • 代码应该以不影响其他Python实现(PyPy,Jython,IronPython,Cython,Psyco等)的方式编写.
    • 库中性能敏感的部分,用’’.join形式来代替.这会确保在所有不同的实现中字符串拼接是线性时间的.
    • 不要依赖于 CPython 在字符串拼接时的优化实现
  • 与单例作比较,像None应该用is或is not,从不使用==操作符
  • is not操作符而不是not … is.虽然这两个表达式是功能相同的,前一个是更可读的,是首选.
  • 始终使用def语句来代替直接绑定了一个lambda表达式的赋值语句.
  • 捕获异常时,尽可能使用明确的异常,而不是用一个空的except:语句.(限制使用空except语句)
  • 绑定异常给一个名字时,最好使用 Python 2.6 里添加的明确的名字绑定语法:
  • 对于所有try / except子句,将try子句限制为必需的绝对最小代码量.同样,这样可以避免屏蔽错误.
  • 坚持使用return语句.函数内的return语句都应该返回一个表达式,或者None.如果一个return语句返回一个表达式,另一个没有返回值的应该用return None清晰的说明,并且在一个函数的结尾应该明确使用一个return语句(如果有返回值的话).
  • 用字符串方法代替字符串模块.
  • 用’’.startswith()和’’.endswith()代替字符串切片来检查前缀和后缀.startswith()和endswith()是更简洁的,不容易出错的.
  • 对象类型的比较应该始终使用isinstance()而不是直接比较.
  • 对于序列(字符串、列表、元组)来说,空的序列为False:
  • 对于序列(字符串、列表、元组)来说,空的序列为False:
  • 不要让字符串对尾随的空格有依赖.这样的尾随空格是视觉上无法区分的,一些编辑器(或者,reindent.py)会将其裁剪掉.
  • 不要用==比较True和False.