PEP 8 代码规范

文档参考地址:

    https://www.python.org/dev/peps/pep-0008/


前言

对pep8 的要求做一个简要的汇总,不保证包括所有内容,主要包括一些代码风格的要求,取其重点进行汇总。如果有时间将会尽力进行全部的翻译。

代码布局

缩进

  • 使用4个空格作为一个缩进层次
  • 当需要换行时,续行应该和所包含的元素垂直对齐或者使用悬垂缩进,也就是第一行不应该有任何参数,续行也应该有缩进来明确其作为一个续航。 
    例如:
# 对齐
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)
# 另外其实有一种可选情况,也就是悬垂缩进可以缩进不为4个空格,比如用两个

  • if的条件过长需要换行时使用以下几种方案
# 没有额外缩进
if (this_is_one_thing and
    this_is_another_thing):
    do_something

# 加上一行注释来使得编辑器更容易支持语法高亮
if (this_is_one_thing and
    this_is_another_thing):
    # 在这里加上一行注释
    do_something()

# 在续行使用额外的缩进
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

  • 列表元素之类的需要后括号结束的,后括号要么和元素对齐要么顶格
# 和元素对齐
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,
]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

使用TAB制表符还是空格?

用空格! 除非你需要和之前就用的TAB的代码保持一致。 
(虽然Py3允许tab和空格混用)

最大行长度

  1. 对于所有行来说,最长79字符
  2. 对于文档字符串或者注释,最长72字符
  3. 太长的就用backslash换行处理,换行规则之前已经说过了

换行的位置和二元运算符怎么处理?

二元运算符在换行符之后,换句话说,换行之后的续行一开始是二元运算符 
比如

income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

空行

  • 顶层函数以及类定义和其他部分用两个空行隔开
  • 类之内的方法定义之间用一个空行隔开
  • 对于一组相关的函数和其他之间可以有额外的空行
  • 可以使用空行来区分逻辑块

源代码编码

  • py3使用utf-8,py2使用ascii
  • py3已经使用utf-8, py2已经使用ascii的源代码不应该有编码声明

import相关

  • 各个import独立成行, 例如
import os
import sys

# 而不是 import os, sys
# 不过可以这样:
from subprocess import Popen, PIPE

  • import应该总是在文件的最上面,在模块注释和文档字符串之后,在模块变量和常量之前
  • 注意import的顺序,各个import的组需要用空行隔开,顺序为:
 - 标准库import
 - 相关的第三方import
 - 本地应用和库的import

  • 一般情况使用绝对的import,但是在包层次比较复杂的时候使用相对import可以更加简洁,则使用相对import
  • 在import一个class的时候,如果不会引起命名冲突,则可以使用from进行import,否则则直接import并且使用全名
  • 应该避免使用利用通配符进行import,也就是避免使用from xxx import *

模块级的特殊名字

模块级的特殊名字,此处特指那些前后都有双下划线的名字, 比如author等,应该被放置在模块文档字符串之后,除from future import的任何import之前,比如

"""This is the example module.

This module does stuff.
"""

from __future__ import barry_as_FLUFL

__all__ = ['a', 'b', 'c']
__version__ = '0.1'
__author__ = 'Cardinal Biggles'

import os
import sys

字符串引号

单双引号都一样,随便用,除非字符串里边有单引号或者有双引号,导致必须使用另外一种

表达式和语句中的空格

“眼中钉”

以下几种情况不要额外加空格:

  • 在各种括号之中,比如spam(ham[1], {eegs: 2})而不是spam( ham[ 1 ], { eggs: 2 } )
  • 在逗号分号和冒号之前
  • 但是如果冒号作为分隔符,则前后都加空格
  • 后面立即跟了一个括号,比如函数调用的函数和括号之间不应该加空格
  • 后面跟的是索引或者切片的中括号,比如a[1]而不是a [1]
  • 对于赋值或者其他操作符,不要为了多个语句对齐而加很多空格,前后一个即可

其他的建议

  • 一行的尾部不要有空格
  • 二元运算符前后始终都最好有一个空格
  • 在一个表达式中有不同优先级的运算符,可以添加空格以区别优先级
  • 在调用函数时作为参数的那个等号则前后不要有空格(虽然看起来像个二元运算符),比如func(a=3, b=4)而不是func(a = 3, b = 4)
  • 带箭头的函数,箭头两端也应该和二元运算符一样,前后有空格def func() -> AnyStr: ...
  • 函数声明的默认参数,只有在有notation的时候前后有等号,否则前后没有等号, 例如
# 这里有等号
def func(sep: AnyStr = None): ...
# 这里没有
def func(sep=None): ...

  • 多条语句最好不要在一行,if之后如果只有一条语句也最好不要在一行,如果有多条,则绝对不要在一行

注释

  • 注释和内容冲突的,比不要注释还那啥,改代码一定要改注释,保证注释最新
  • 注释应该是完整的句子,如果一个注释是一个短语或者句子,首字母大写,除非是小写字母开头的标识符作为开头
  • 短注释结尾的句号可以省略,包含一个或多个段落的块注释每一个句子都应该有句号
  • 在句子结束的句号之后应该有两个句号
  • 用英语写的时候,遵守Strunk and White写作风格
  • 除非你十分确定你的代码不会被任何不用你这个语言的人使用,否则都用英语写注释

块注释

用来解释之后的代码,和之后的代码保持一致的缩进,每一行由井号#和一个空格开始, 块注释里的段落用只包含一个井号的一行隔开

行内注释

  • 保守点使用行内注释
  • 和语句最少有两个空格
  • 对于显然的东西不要加行内注释,只解释看上去不那么显然的

文档字符串

  • 对于所有公用模块,函数,类和方法,都要写文档字符串。但是对于非公用的方法可以不用,但是你应该注释好这个方法干了些啥,这个注释在def一行之后
  • pep 257描述了怎么样写文档字符串最好,最重要的是,”“”用来结束一个多行文档字符串应该的时候应该独立成行
  • 如果仅仅是一行的文档字符串,”“”可以在同一行

命名规则

重载规则(Overriding Principle)

API中对于用户可见的公用部分的命名应该体现他们的用法而不是实现 
##命名风格

命名主要是以下几种: 
- b (单小写字母) 
- B (单大写字母) 
- lowercase (小写) 
- lower_case_with_underscores (带下划线的小写形式) 
- UPPERCASE (大写) 
- UPPER_CASE_WITH_UNDERSCORES (带下划线的大写形式) 
- CapitalizedWords (开头大写的单词组,如果含有缩写,缩写部分全大写,比如HTTP) 
- mixedCase (第一个单词首字母小写,后面开头大写) 
- Capitalized_Words_With_Underscores (丑死了!)

另外,以下几种特殊情况将会被特殊对待:

  • _single_leading_underscore:开头单下划线,是表示内部使用的,import的时候就会被忽略
  • single_trailing_underscore_:结尾单下划线,表示和python的关键字避免冲突使用
  • __double_leading_underscore: 开头双下划线,可以粗浅的认为类似类中private
  • double_leading_underscore_and_trailing_underscore: “魔法”对象或者属性,比如init等等,不要自己写这种名字

命名传统

需要避免的名字

永远不要使用’l’(小写字母el), ‘O’(大写字母欧),’I’(大写字母哎)作为单字母的变量, 实在要用小写l(el)的时候可以用大写形式L代替

包和模块名

  • 模块名:短小,全小写,如果能够提高可读性,用下划线
  • 包名:短小,全小写,不过别用下划线
  • 如果是用C或者C++写的python module,名字前单下划线

类名

  • 类名用大写开头的词组形式,CapWords这种形式
  • 有的时候也可以用函数那种形式,如果是可以调用的情况的话

类型变量名

一般使用大写开头的短名字:T, AnyStr, Num之类。 推荐加上后缀_co或者_contra来表示covarient或者cotravariant的行为。

异常名

异常也是类,用类的命名就可以,不过应该使用“Error”作为后缀(如果是error的话) 
###全局变量名 
模块应该使用all机制来保证不会导出所有的符号,或者用前缀加下划线的方式来表示全局变量

函数名

小写,下划线隔开单词,除非已经有mixedCase(首字母小写,后面单词首字母大写)这种形式,否则都不要用mixedCase,而是用下划线隔开小写单词的形式。

函数和方法参数

  • 实例方法第一个参数始终使用self
  • 类方法的第一个参数始终使用cls
  • 如果函数参数和保留字冲突了,最好使用一个下划线作为后缀,而非使用简写(和java等等区分开)

方法名和实例变量

  • 使用函数名规则
  • 非公用的方法和实例变量添加一个前缀单下划线
  • 为避免和子类命名冲突,使用双下划线前缀来保证
  • 双下划线会使得python在处理的时候将类名添加上去以区分,比如Foo里的__a将会变为_Foo__a,这样就会区分开了

常量

全大写,下划线隔开

继承的设计

  • 考虑好一个类的方法和实例变量是公有还是非公有,如果不确定就私有。
  • 公有属性没有前缀的下划线
  • 如果公有属性名和保留字冲突,尾部添加一个下划线
  • 对于简单的数据属性,最好只暴露属性名,不要有复杂的accessor和mutator方法。
  • 如果这个类是用来被继承的,有一些属性你不希望子类继承,考虑使用前缀双下划线

公有和内部接口

(略,暂时感觉不太重要,如有需要之后补上)

编程推荐

  • 代码应该不使得其他python实现有劣势,也就是不要依靠特定的python实现来提高效率
  • 和单例(Singleton),比如None比较,应该一直使用is和is not而不是等于符号和不等于
  • 使用is not运算符而不是使用not … is
  • 如果实现比较运算密集的有序操作时,最好实现所有的六种操作(eqneltlegtge)
  • 定义有名字的函数始终使用def而不是通过lambda表达式来赋值
  • 从Exception继承而不是从BaseException
  • 恰当的使用exception链
  • 在py2里边raise一个异常的时候,使用raise ValueError('message')而不是raise ValuError, 'message', py3中后面的方法会出错
  • 捕捉异常的时候,使用具体的异常,而不是用一个单纯的except:xxx,否则连SystemExit和KeyboardInterrupt也会被捕捉到
  • 给异常绑定名字的时候使用py2.6添加的as的方法,except Exception as exc:...
  • 捕捉系统错误的时候,使用py3.3添加的异常阶层而不是使用errno值
  • try语句包含的东西越少越好
  • 如果一个资源是一段代码本地使用的,使用with语句保证被正确释放
  • 上下文管理器始终应该使用函数或者方法来调用
  • 保证返回语句一致,要么所有情况都有返回,要么都没有
  • 使用字符串方法,而不是使用字符串模块
  • 使用''.startswith()''.endswith()而不是字符串切片来检查前缀后缀
  • 对象类型的比较应该使用isinstance()而不是直接比较
  • 对于序列(字符串,列表,元组),可以利用空序列为false
  • 字符串字面量不要依赖有意义的尾部空白
  • 布尔值不要用==和is来比较,直接用if is_true:...而不是if is_true == True:更不要用if is_true is True:...

函数注解

(略)

猜你喜欢

转载自blog.csdn.net/zhangyu4863/article/details/80211719