【转】PEP8备忘

来源:互联网 发布:软件管家官方版 编辑:程序博客网 时间:2024/06/08 09:35

出处

译版:
_ Damnever’s blog : http://damnever.github.io/2015/04/24/PEP8-style-guide-for-python-code/ _
原版:
https://www.python.org/dev/peps/pep-0008/

代码排版

缩进

每层缩进使用4个空格。

续行要么与圆括号、中括号、花括号这样的被包裹元素保持垂直对齐,要么放在 Python 的隐线(注:应该是相对于def的内部块)内部,或者使用悬挂缩进5。使用悬挂缩进的注意事项:第一行不能有参数,用进一步的缩进来把其他行区分开。

好的:

# Aligned with opening delimiter.foo = long_function_name(var_one, var_two,                         var_three, var_four)## More indentation included to distinguish this from the rest.def long_function_name(        var_one, var_two, var_three,        var_four):    print(var_one)## Hanging indents should add a level.foo = long_function_name(    var_one, var_two,    var_three, var_four)

不好的:

# Arguments on first line forbidden when not using vertical alignment.foo = long_function_name(var_one, var_two,    var_three, var_four)## Further indentation required as indentation is not distinguishable.def long_function_name(    var_one, var_two, var_three,    var_four):    print(var_one)

4空格规则是可选的:

# Hanging indents *may* be indented to other than 4 spaces.foo = long_function_name(  var_one, var_two,  var_three, var_four)

当 if 语句的条件部分足够长,需要将它写入到多个行,值得注意的是两个连在一起的关键字(i.e. if),添加一个空格,给后续的多行条件添加一个左括号形成自然地4空格缩进。如果和嵌套在 if 语句内的缩进代码块产生了视觉冲突,也应该被自然缩进4个空格。这份增强建议书对于怎样(或是否)把条件行和 if 语句的缩进块在视觉上区分开来是没有明确规定的。可接受的情况包括,但不限于:

# No extra indentation.if (this_is_one_thing and    that_is_another_thing):    do_something()# Add a comment, which will provide some distinction in editors# supporting syntax highlighting.if (this_is_one_thing and    that_is_another_thing):    # Since both conditions are true, we can frobnicate.    do_something()# Add some extra indentation on the conditional continuation line.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)应该被用在那些以前就使用了制表符缩进的地方。

Python 3 不允许混合使用制表符和空格来缩进代码。

混合使用制表符和空格缩进的 Python 2 代码应该改为只使用空格。

当使用 -t 选项来调用 Python 2 的命令行解释器的时候,会对混合使用制表符和空格的代码发出警告。当使用 -tt 选项的时候,这些警告会变成错误。这些选项是强烈推荐的!

每行最大长度

限制每行的最大长度为79个字符。

对于那些约束很少的文本结构(文档字符串或注释)的长块,应该限制每行长度为72个字符。

限制编辑窗口的宽度使并排打开两个窗口成为可能,使用通过代码审查工具时,也能很好的通过相邻列展现不同代码版本。

一些工具的默认换行设置打乱了代码的可视结构,使其更难理解。限制编辑器窗口宽为80来避免自动换行,即使有些编辑工具在换行的时候会在最后一列放一个标识符。一些基于 Web 的工具可能根本就不提供动态换行。

一些团队更倾向于长的代码行。对于达成了一致意见来统一代码的团队而言,把行提升到80~100的长度是可接受的(实际最大长度为99个字符),注释和文档字符串的长度还是建议在72个字符内。

Python 标准库是非常专业的,限制最大代码长度为79个字符(注释和文档字符串最大长度为72个字符)。

首选的换行方式是在括号(小中大)内隐式换行(非续行符\)。长行应该在括号表达式的包裹下换行。这比反斜杠作为续行符更好。

反斜杠有时仍然适用。例如,多个很长的with语句不能使用隐式续行,因此反斜杠是可接受的。

with open('/path/to/some/file/you/want/to/read') as file_1, \     open('/path/to/some/file/being/written', 'w') as file_2:    file_2.write(file_1.read())

空行

顶级函数和类定义上下使用两个空行分隔。

类内的方法定义使用一个空行分隔。

可以使用额外的空行(有节制的)来分隔相关联的函数组。在一系列相关联的单行代码中空行可以省略(e.g. 一组虚拟的实现)。

在函数中使用空白行(有节制的)来表明逻辑部分。

Python 接受使用换页符(i.e. Ctrl+L)作为空格;许多工具都把Ctrl+L作为分页符,因此你可以用它们把你的文件中相似的章节分页。注意,一些编辑器和基于 Web 的代码查看工具可能不把Ctrl+L看做分页符,而是在这个位置放一个其它的符号。

导包

import不同的模块应该独立一行,如:

好的:

import osimport sys

不好的:

import sys, os

这样也是可行的:

from subprocess import Popen, PIPE
  • import语句应该总是放在文件的顶部,在模块注释和文档字符串之下,在模块全局变量和常量之前。

  • import语句分组顺序如下:

    导入标准库模块
    导入相关第三方库模块
    导入当前应用程序/库模块

  • 应该避免通配符导入(from <module> import *),这会使名称空间里存在的名称变得不清晰,迷惑读者和自动化工具。这里有一个可辩护的通配符导入用例,,重新发布一个内部接口作为公共 API 的一部分(例如,使用纯 Python 实现一个可选的加速器模块的接口,但并不能预知这些定义会被覆盖)。

字符串引号

在 Python 里面,单引号字符串和双引号字符串是相同的。这份指南对这个不会有所建议。选择一种方式并坚持使用。一个字符串同时包含单引号和双引号字符时,用另外一种来包裹字符串,而不是使用反斜杠来转义,以提高可读性。

对于三引号字符串,总是使用双引号字符来保持与文档字符串约定的一致性(PEP 257)。

表达式和语句中的空格

不能忍受的情况

避免在下列情况中使用多余的空格:

  • 与括号保持紧凑(小括号、中括号、大括号):
Yes: spam(ham[1], {eggs: 2})No:  spam( ham[ 1 ], { eggs: 2 } )
  • 与后面的逗号、分号或冒号保持紧凑:
Yes: if x == 4: print x, y; x, y = y, xNo:  if x == 4 : print x , y ; x , y = y , x
  • 切片内的冒号就像二元操作符一样,任意一侧应该被等同对待(把它当做一个极低优先级的操作)。在一个可扩展的切片中,冒号两侧必须有相同的空格数量。例外:切片参数省略时,空格也省略。

好的:

ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]ham[lower:upper], ham[lower:upper:], ham[lower::step]ham[lower+offset : upper+offset]ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]ham[lower + offset : upper + offset]

不好的:

ham[lower + offset:upper + offset]ham[1: 9], ham[1 :9], ham[1:9 :3]ham[lower : : upper]ham[ : upper]
  • 函数名与其后参数列表的左括号应该保持紧凑:
Yes: spam(1)No:  spam (1)
  • 与切片或索引的左括号保持紧凑:
Yes: dct['key'] = lst[index]No:  dct ['key'] = lst [index]
  • 在复制操作符(或其它)的两侧保持多余一个的空格:

好的:

x = 1y = 2long_variable = 3

不好的:

x             = 1y             = 2long_variable = 3

注释

与代码相矛盾的注释不如没有。注释总是随着代码的变更而更新。

注释应该是完整的句子。如果注释是一个短语或语句,第一个单词应该大写,除非是一个开头是小写的标识符(从不改变标识符的大小写)。

如果注释很短,末尾的句点可以省略。块注释通常由一个或多个有完整句子的段落组成,并且每个句子应该由句点结束。

你应该在一个句子的句点后面用两个空格。

写英语时,遵循《Strunk and White》(注:《英文写作指南》,参考维基百科)。

来自非英语国家的程序员:请用英语写注释,除非你120%确定你的代码永远不会被那些不说你的语言的人阅读。

块注释

块注释通常用来说明跟随在其后的代码,应该与那些代码有相同的缩进层次。块注释每一行以#起头,并且#后要跟一个空格(除非是注释内的缩进文本)。

行内注释

有节制的使用行内注释。

一个行内注释与语句在同一行。行内注释应该至少与语句相隔两个空格。以#打头,#后接一个空格。

无谓的行内注释如果状态明显,会转移注意力。不要这样做:

x = x + 1                 # Increment x

但有的时候,这样是有用的:

x = x + 1                 # Compensate for border

文档字符串

编写良好的文档字符串(a.k.a “docstring”)的约定常驻在 PEP 257

  • 为所有的公共模块、函数、类和方法编写文档字符串。对于非公共的方法,文档字符串是不必要的,但是也应该有注释来说明代码是干什么的。这个注释应该放在方法声明的下面。

  • PEP 257 描述了良好的文档字符串的约定。注意,文档字符串的结尾”“”应该放在单独的一行,例如:

"""Return a foobangOptional plotz says to frobnicate the bizbaz first."""
  • 对于单行的文档字符串,把结尾”“”放在同一行。

版本注记

如果必须要 Subversion,CVS 或 RCS 标记在你的源文件里,像这样做:

__version__ = "$Revision$"# $Source$

这几行应该在模块的文档字符串后面,其它代码的前面,上下由一个空行分隔。

命名约定

Python 库的命名规则有点混乱,因此我们永远也不会使其完全一致的 – 不过,这里有一些当前推荐的命名标准。新的模块和包(包括第三方框架)应该按照这些标准来命名,但是已存在库有不同的风格,内部一致性是首选。

覆盖原则

API 里对用户可见的公共部分应该遵循约定,反映的是使用而不是实现。

规定:命名约定

有许多不同的命名风格。这有助于识别正在使用的命名风格,独立于它们的用途。

下面的命名风格通常是有区别的:

  • b (一个小写字母)
  • B (一个大写字母)
  • lowercase
  • lower_case_with_underscores
  • UPPERCASE
  • UPPER_CASE_WITH_UNDERSCORES
  • CapitalizedWords (又叫 CapWords,或者 CamelCase(骆驼命名法) – 如此命名因为字母看起来崎岖不平[3])。有时候也叫 StudlyCaps。
    注意:在 CapWords 使用缩略语时,所有缩略语的首字母都要大写。因此HTTPServerErrorHttpServerError要好。

  • mixedCase (和上面不同的是首字母小写)

  • Capitalized_Words_With_Underscores (丑陋无比!)

也有种风格用独一无二的短前缀来将相似的命名分组。在 Python 里用的不是很多,但是为了完整性被提及。例如,os.stat()函数返回一个元组,通常有像st_modest_sizest_mtime等名字。(强调与 POSIX 系统调用的字段结构一致,有助于程序员对此更熟悉)

X11 库的所有公共函数都用 X 打头。在 Python 中这种风格被认为是不重要的,因为属性和方法名的前缀是一个对象,函数名的前缀为一个模块名。

此外,下面的特许形式用一个前导或尾随的下划线进行识别(这些通常可以和任何形式的命名约定组合):

  • _single_leading_underscore :仅内部使用的标识,如from M import *不会导入像这样一下划线开头的对象。

  • single_trailing_underscore_ : 通常是为了避免与 Python 规定的关键字冲突,如Tkinter.Toplevel(master, class_='ClassName')

  • __double_leading_underscore : 命名一个类属性,调用的时候名字会改变(在类FooBar中__boo变成了_FooBar__boo;见下)。

  • double_leading_and_trailing_underscore :”魔术”对象或属性,活在用户控制的命名空间里。例如,__init____import____file__。永远不要像这种方式命名;只把它们作为记录。

应该避免的名字

永远不要使用单个字符l(小写字母 el),O(大写字母 oh),或I(大写字母 eye)作为变量名。

在一些字体中,这些字符是无法和数字10区分开的。试图使用l时用L代替。

包和模块名

模块名应该短,且全小写。如果能改善可读性,可以使用下划线。Python 的包名也应该短,全部小写,但是不推荐使用下划线。

因为模块名就是文件名,而一些文件系统是大小写不敏感的,并且自动截断长文件名,所以给模块名取一个短小的名字是非常重要的 – 在 Unix 上这不是问题,但是把代码放到老版本的 Mac, Windows,或者 DOS 上就可能变成一个问题了。

用 C/C++ 给 Python 写一个高性能的扩展(e.g. more object oriented)接口的时候,C/C++ 模块名应该有一个前导下划线。

类名

类名通常使用 CapWords 约定。

The naming convention for functions may be used instead in cases where the interface is documented and used primarily as a callable.

注意和内建名称的区分开:大多数内建名称是一个单独的单词(或两个单词一起),CapWords 约定只被用在异常名和内建常量上。

异常名

因为异常应该是类,所以类名约定在这里适用。但是,你应该用Error作为你的异常名的后缀(异常实际上是一个错误)。

全局变量名

(我们希望这些变量仅仅在一个模块内部使用)这个约定有关诸如此类的变量。

若被设计的模块可以通过from M import *来使用,它应该使用__all__机制来表明那些可以可导出的全局变量,或者使用下划线前缀的全局变量表明其是模块私有的。

函数名

函数名应该是小写的,有必要的话用下划线来分隔单词提高可读性。

混合大小写仅仅在上下文都是这种风格的情况下允许存在(如thread.py),这是为了维持向后兼容性。

函数和方法参数

总是使用self作为实例方法的第一个参数。

总是使用cls作为类方法的第一个参数。

如果函数参数与保留关键字冲突,通常最好在参数后面添加一个尾随的下划线,而不是使用缩写或胡乱拆减。因此class_clss要好。(或许避免冲突更好的方式是使用近义词)

方法名和实例变量

用函数名的命名规则:全部小写,用下划线分隔单词提高可读性。

用一个且有一个前导的下划线来表明非公有的方法和实例变量。

为了避免与子类变量或方法的命名冲突,用两个前导下划线来调用 Python 的命名改编规则。

Python 命名改编通过添加一个类名:如果类Foo有一个属性叫__a,它不能被这样Foo.__a访问(执着的人可以通过这样Foo._Foo__a来访问)通常,双前导的下划线应该仅仅用来避免与其子类属性的命名冲突。

注意:这里有一些争议有关__names的使用(见下文)。

常量

常量通常是模块级的定义,全部大写,单词之间以下划线分隔。例如MAX_OVERFLOWTOTAL

继承的设计

总是决定一个类的方法和变量(属性)是应该公有还是非公有。如果有疑问,选择非公有;相比把共有属性变非公有,非公有属性变公有会容易得多。

公有属性是你期望给那些与你的类无关的客户端使用的,你应该保证不会出现不向后兼容的改变。非公有的属性是你不打算给其它第三方使用的;你不需要保证非公有的属性不会改变甚至被移除也是可以的。

我们这里不适用“私有”这个术语,因为在 Python 里没有真正的私有属性(一般没有不必要的工作量)。

另一种属性的分类是“子类 API”的一部分(通常在其它语言里叫做“Protected”)。一些类被设计成被继承的,要么扩展要么修改类的某方面行为。设计这样一个类的时候,务必做出明确的决定,哪些是公有的,其将会成为子类 API 的一部分,哪些仅仅是用于你的基类的。

处于这种考虑,给出 Pythonic 的指南:

  • 共有属性不应该有前导下划线。
  • 如果你的公有属性与保留关键字发生冲突,在你的属性名后面添加一个尾随的下划线。这比使用缩写或胡乱拆减要好。(尽管这条规则,已知某个变量或参数可能是一个类情况下,cls是首选的命名,特别是作为类方法的第一个参数)

注意一:见上面推荐的类方法参数命名方式。

  • 对于简单的公有数据属性,最好的方式是暴露属性名,不要使用复杂的访问属性/修改属性的方法。记住,Python 提供了捷径去提升特性,如果你发现简单的数据属性需要增加功能行为。在这种情况下,使用properties把功能实现隐藏在简单的数据属性访问语法下面。

注意一:properties仅仅在新式类下工作。   注意二:尽量保持功能行为无边际效应,然而如缓存有边际效应也是好的。   注意三:避免为计算开销大的操作使用properties;属性标记使调用者相信这样来访问(相对来说)是开销很低的。

  • 如果你的类是为了被继承,你有不想让子类使用的属性,给属性命名时考虑给它们加上双前导下划线,不要加尾随下划线。这会调用 Python 的名称重整算法,把类名加在属性名前面。避免了命名冲突,当子类不小心命名了和父类属性相同名称的时候。

注意一:注意只是用了简单的类名来重整名字,因此如果子类和父类同名的时候,你仍然有能力避免冲突。

注意二:命名重整有确定的用途,例如调试和__getattr__(),就不太方便。命名重整算法是有据可查的,易于手动执行。

注意三:不是每个人都喜欢命名重整。尽量平衡名称的命名冲突与面向高级调用者的潜在用途。

公共和内部接口

保证所有公有接口的向后兼容性。用户能清晰的区分公有和内部接口是重要的。

文档化的接口考虑公有,除非文档明确的说明它们是暂时的,或者内部接口不保证其的向后兼容性。所有的非文档化的应该被假设为非公开的。

为了更好的支持内省,模块应该用__all__属性来明确规定公有 API 的名字。设置__all__为空list表明模块没有公有 API。

甚至与__all__设置相当,内部接口(包、模块、类、函数、属性或者其它的名字)应该有一个前导的下划线前缀。

被认为是内部的接口,其包含的任何名称空间(包、模块或类)也被认为是内部的。

导入的名称应始终视作一个实现细节。其它模块不能依赖间接访问这些导入的名字,除非它们是包含模块的 API 明确记载的一部分,例如os.path或一个包的__init__模块暴露了来自子模块的功能。

0 0