PEP 8 — Python代码风格指南

Kenneth Reitz 创建的优秀 PEP 8 的(人性化)风格化呈现.

介绍

This document gives coding conventions for the Python code comprising the standard library in the main Python distribution. Please see the companion informational PEP describing style guidelines for the C code in the C implementation of Python 1.
这篇文档,描述了在Python主发行版中,标准库代码所遵循的规范。对于Python的C语言实现中采用的编码规范,请参考实现Python的C代码风格指南 1

This document and PEP 257 (Docstring Conventions) were adapted from Guido’s original Python Style Guide essay, with some additions from Barry’s style guide 2.
本文档与 PEP 257 (Docstring 约定) 均改编自Guido最早的Python风格指南文章,并添加了一些Barry风格指南2中的内容。

This style guide evolves over time as additional conventions are identified and past conventions are rendered obsolete by changes in the language itself.
语言自身在不断发生改变,随着新约定不断涌现、老约定渐渐淘汰,本风格指南也会随时间推移不断发展。

Many projects have their own coding style guidelines. In the event of any conflicts, such project-specific guides take precedence for that project.
很多项目都有自己的一套代码风格规范,如果和本指南有任何冲突,应以项目自身规范为先。

不要为一致性而一致性

One of Guido’s key insights is that code is read much more often than it is written. The guidelines provided here are intended to improve the readability of code and make it consistent across the wide spectrum of Python code. As PEP 20 says, “Readability counts”.
Guido的重要观点之一,就是代码被用来看的频率,远高于写的频率。本指南旨在改善代码的可读性,使其在各种不同的Python代码中保持一致。诚如PEP 20《Python之禅(Zen of Python)》所言:“可读性至上(Readability counts)”。

A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is the most important.
风格指南讲的就是一致性。跟本风格指南保持一致很重要。在项目内部保持一致,则更为重要。在一个模块、函数内部保持一致,则更更重要。

However, know when to be inconsistent—sometimes style guide recommendations just aren't applicable. When in doubt, use your best judgment. Look at other examples and decide what looks best. And don’t hesitate to ask!
不过,要知道什么情况需要不一致——有时,风格指南的建议并不适用。如果心存疑虑,运用自己最佳的判断力。看看其他例子,决定怎样看起来更好。别犹豫,开口去问!

In particular: do not break backwards compatibility just to comply with this PEP!
特别是:不要为了遵循本PEP,破坏向后兼容性!

Some other good reasons to ignore a particular guideline:
忽略某条指南建议的其他好理由: :

 
  1. When applying the guideline would make the code less readable, even for someone who is used to reading code that follows this PEP.
    当遵循该指南,会让代码可读性降低,甚至让那些习惯读遵循本PEP风格代码的人都觉得难懂时。
  2. To be consistent with surrounding code that also breaks it (maybe for historic reasons) – although this is also an opportunity to clean up someone else’s mess (in true XP style).
    为了和周围与指南风格相悖(可能出于历史原因)的代码保持一致————尽管这也是收拾别人烂摊子的好机会(真正的XP极限编程风格)。
  3. Because the code in question predates the introduction of the guideline and there is no other reason to be modifying that code.
    因为有冲突的代码早于指南的引入,也没有其他理由修改该代码。
  4. When the code needs to remain compatible with older versions of Python that don’t support the feature recommended by the style guide.
    当代码需要与不支持风格指南所建议特性的老版Python保持兼容时。

代码布局

缩进

Use 4 spaces per indentation level.
每级缩进用4个空格。

Continuation lines should align wrapped elements either vertically using Python’s implicit line joining inside parentheses, brackets and braces, or using a hanging indent 3. When using a hanging indent the following should be considered; there should be no arguments on the first line and further indentation should be used to clearly distinguish itself as a continuation line.
续行部分,可以用Python的隐式续行,在圆括号、方括号或花括号内垂直对齐包含的元素,或者用悬挂缩进(hanging indent)3。悬挂缩进时,要考虑两点:第一行不应有参数出现,需要时续行中要再加一级缩进,以清楚区分续行和新行。

Yes:

# 和开始分界符(左括号)对齐
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)

No:

# 垂直对齐时第一行不应该有参数
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)

The 4-space rule is optional for continuation lines.
对续行来说,不一定非要用4个空格表示缩进。

Optional:
这样也可以:

# 悬挂缩进可以不用4个空格表示缩进
foo = long_function_name(
  var_one, var_two,
  var_three, var_four)

When the conditional part of an if-statement is long enough to require that it be written across multiple lines, it’s worth noting that the combination of a two character keyword (i.e. if), plus a single space, plus an opening parenthesis creates a natural 4-space indent for the subsequent lines of the multiline conditional. This can produce a visual conflict with the indented suite of code nested inside the if-statement, which would also naturally be indented to 4 spaces. This PEP takes no explicit position on how (or whether) to further visually distinguish such conditional lines from the nested suite inside the if-statement. Acceptable options in this situation include, but are not limited to:
如果if语句的条件太长、要分成多行,请注意,两个字符的关键字(如if等)加上空格和左括号,宽度正好和4个空格一样,续行部分缩进自然也是4个空格,而if语句中嵌套的其他代码缩进也是4个空格,不好轻易区分。本PEP不强制规定如何区分续行条件语句和if语句中嵌套的其他代码。以下几种方法都可以,也可以考虑其他方法:

# 不另外加缩进
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

# 增加一行注释,编辑器高亮时就能区分得开
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

# 续行的条件语句加一级缩进
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

(Also see the discussion of whether to break before or after binary operators below.)
(另请参见下面关于在二元操作符之前还是之后换行的讨论)

The closing brace/bracket/parenthesis on multiline constructs may either line up under the first non-whitespace character of the last line of list, as in:
多行续行结束时,最后一个右圆括号/方括号/花括号,可以单起一行,和上一行首个非空白字符对齐,像这样:

my_list = [
    1, 2, 3,
    4, 5, 6,
    ]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )

or it may be lined up under the first character of the line that starts the multiline construct, as in:
也可以和多行续行开始那一行首个字符对齐:

my_list = [
    1, 2, 3,
    4, 5, 6,
]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

用Tab还是用空格?

Spaces are the preferred indentation method.
建议用空格进行缩进。

Tabs should be used solely to remain consistent with code that is already indented with tabs.
只有在已有代码用Tab缩进时,为了与之保持一致,才使用Tab。

Python 3 disallows mixing the use of tabs and spaces for indentation.
Python 3不允许混合使用Tab和空格进行缩进。

Python 2 code indented with a mixture of tabs and spaces should be converted to using spaces exclusively.
Python 2有Tab、空格混用的情况,应把Tab全部转换为空格。

When invoking the Python 2 command line interpreter with the -t option, it issues warnings about code that illegally mixes tabs and spaces. When using -tt these warnings become errors. These options are highly recommended!
用命令行运行Python 2时,用-t选项,混用Tab和空格会出现非法使用的警告。用-tt选项,警告会升级为错误。强烈推荐使用这些选项!

单行最大长度

Limit all lines to a maximum of 79 characters.
把所有行长度限制在79个字符。

For flowing long blocks of text with fewer structural restrictions (docstrings or comments), the line length should be limited to 72 characters.
对于连续大段、结构限制又较少的文字(如文档字符串(docstring)或注释),行长度应限制为72个字符。

Limiting the required editor window width makes it possible to have several files open side-by-side, and works well when using code review tools that present the two versions in adjacent columns.
限制编辑器的窗口宽度,可以让多个文件并排显示在屏幕上,在用代码评审(code review)工具时,可在两个相邻窗口显示两个版本的代码而不影响效果。

The default wrapping in most tools disrupts the visual structure of the code, making it more difficult to understand. The limits are chosen to avoid wrapping in editors with the window width set to 80, even if the tool places a marker glyph in the final column when wrapping lines. Some web based tools may not offer dynamic line wrapping at all.
很多工具的默认自动换行功能,会破坏代码结构,使代码更难以理解。选择限制长度,是为了避免在窗口宽度设置为80的编辑器中换行,即使工具在换行时在最后一列放置了标记符号。一些网页版工具可能根本就不提供动态换行。

Some teams strongly prefer a longer line length. For code maintained exclusively or primarily by a team that can reach agreement on this issue, it is okay to increase the line length limit up to 99 characters, provided that comments and docstrings are still wrapped at 72 characters.
有些团队强烈希望采用更长的单行代码长度。如果代码仅由或主要由能就此问题达成一致的团队维护,可将行长度限制增加到99个字符,但注释和文档字符串仍应遵循72字符换行。

The Python standard library is conservative and requires limiting lines to 79 characters (and docstrings/comments to 72).
Python标准库比较保守,要求将单行限制在79字符以内(文档字符串/注释限制在72字符)。

The preferred way of wrapping long lines is by using Python’s implied line continuation inside parentheses, brackets and braces. Long lines can be broken over multiple lines by wrapping expressions in parentheses. These should be used in preference to using a backslash for line continuation.
一种推荐的长行换行方式,是用Python的圆括号、方括号或花括号进行隐式续行。长行可通过在括号内换行来分成多行。最好加上反斜杠以区别续行。

Backslashes may still be appropriate at times. For example, long, multiple with-statements cannot use implicit continuation, so backslashes are acceptable:
有时续行只能用反斜杠。例如,较长的、包含多个部分的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())

(See the previous discussion on multiline if-statements for further thoughts on the indentation of such multiline with-statements.)
(这里with语句的缩进可参照前面关于 多行if语句缩进的讨论)

Another such case is with assert statements.
另一个类似的例子是assert语句。

Make sure to indent the continued line appropriately.
请确保续行具有适当的缩进。

Should a Line Break Before or After a Binary Operator?
在二元操作符之前还是之后进行换行?

For decades the recommended style was to break after binary operators. But this can hurt readability in two ways: the operators tend to get scattered across different columns on the screen, and each operator is moved away from its operand and onto the previous line. Here, the eye has to do extra work to tell which items are added and which are subtracted:
长期以来推荐风格是在二元操作符之后换行。但是这样会影响代码可读性,原因有二:一是运算符会分布在屏幕上的不同列上(参差不齐),二是操作符会留在前一行、远离右边的操作数。读代码的时候眼睛要费点劲,才能看清谁被加了,谁又被减了:

# No: 操作符远离操作数
income = (gross_wages +
          taxable_interest +
          (dividends - qualified_dividends) -
          ira_deduction -
          student_loan_interest)

To solve this readability problem, mathematicians and their publishers follow the opposite convention. Donald Knuth explains the traditional rule in his Computers and Typesetting series:
为了解决可读性问题,数学家和出版商遵循相反的惯例,Donald Knuth在他的电脑与排版系列中解释了传统的规则:

“Although formulas within a paragraph always break after binary operations and relations, displayed formulas always break before binary operations” 4.
“虽然段落中的公式总是在二元操作和关联之后换行,但显示公式时总是在二元操作之前中断”4.

遵循数学传统往往会产生更易读的代码:

# Yes: 匹配操作符和操作数更容易
income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

Python代码中,在二元操作符之前或之后换行都可以,只要按约定在局部保持一致即可。对于新的代码,建议直接用Knuth风格。

空行

用2个空行来分隔最外层的函数(function)和类(class)定义。

用1个空行来分隔类中的方法(method)定义。

可以(尽量少)用额外的空行来分隔相关成组的函数。在一系列相关且仅占一行的函数间,空行可以省略(比如一组伪实现(dummy implementation))。

在函数内,(尽量少)用空行以使代码逻辑更清晰。

Python支持control-L(如:^L)换页符作为空格;许多工具将这些符号看做分页符,你可以用它们将文件相关部分分隔成单独的页。请注意,一些编辑器和网页版代码查看器可能不会将control-L识别为分页符,而是将其显示为其他符号。

源文件编码

Python核心发行版代码总是用UTF-8编码(Python 2中用ASCII)。

用ASCII编码(Python 2)或者UTF-8编码(Python 3)的文件不用添加编码声明。

在标准库中,只有用于测试目的、注释或文档字符串为提及作者名字不得不用非ASCII字符时,才能用非默认编码。否则,在字符串文字中包括非ASCII数据时,推荐使用\x, \u, \U, 或 \N等转义符号。

对于Python 3.0及其以后的版本中,标准库遵循以下原则(参见PEP 3131):Python标准库中所有标识符,只能用ASCII编码,能用英文单词的情况下*应尽量*使用英文单词(很多情况,缩写和技术术语并不是英文单词)。此外,字符串文字和注释应该只包括ASCII编码。只有两种情况属于例外:(a) 在测试用例中测试非ASCII编码特性 (b) 作者名字。作者名字不是由拉丁字母(latin-1, ISO/IEC 8859-1字符集)组成的,也必须提供该编码的音译名。

对于面向全球受众的开源项目,建议采用类似原则。

Imports

  • Import应该每行一个、单独写。

    Yes:

    import os
    import sys

    No:

    import os, sys

    当然,这样写是可以的:

    from subprocess import Popen, PIPE
  • Imports总是位于代码文件的开头,在模块(module)注释和文档字符串(docstring)之后、模块全局变量(globals)和常量(constants)声明之前。

    Imports按如下顺序分组写:

    1. 标准库imports
    2. 相关第三方imports
    3. 本地应用/库特定imports

    不同组imports之间用空行隔开。

  • 推荐用绝对imports(absolute imports),一方面更易读,另一方面,就算import系统配置有问题(比如包中路径以sys.path结尾),也能表现得更好一些(至少会给出错误信息):

    import mypkg.sibling
    from mypkg import sibling
    from mypkg.sibling import example

    不过,除绝对imports之外,显式的相对imports,也是一种可以接受的替代方式。特别是包布局(package layouts)比较复杂时,用绝对imports会显得有些啰嗦:

    from . import sibling
    from .sibling import example

    标准库代码总是用绝对imports,并避免复杂的包布局。

    绝对不用隐式的相对imports,在Python 3中已经被去掉了。

  • 从包含类的模块中import类,通常可以这样写:

    from myclass import MyClass
    from foo.bar.yourclass import YourClass

    如果拼写和本地命名发生冲突,直接import模块:

    import myclass
    import foo.bar.yourclass

    然后用myclass.MyClassfoo.bar.yourclass.YourClass引用类。

  • 避免用通配符import(from <module> import *),这样会造成当前命名空间搞不清哪些名字已用,给读者和自动化工具造成困扰。有一种情况可使用通配符import:将内部接口再发布成公用API的一部分(比如,用候选加速模块中的定义,覆盖纯Python实现的接口,预先无法知晓具体哪些定义将被覆盖)。

    以这种方式再发布命名时,后面关于公共接口和内部接口的准则依然适用。

模块级双下划线命名

模块级“双下滑线”(名字开头有两个下划线,结尾也有两个下划线)变量,如__all__, __author__, __version__等,应该放在模块文档字符串(docstring)之后、所有import语句之前,除非是from __future__ imports。Python要求,在模块中from __future__ imports必须出现在除文档字符串(docstring)之外的所有代码之前。

"""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

字符串的引用

在Python中,用单引号或双引号表示字符串都是一样的。但PEP不推荐两者混用。可以选择其中一种,坚持用下去。字符串包含单引号时,用双引号来表示字符串,反之亦然,可以避免用反斜杠转义,提高可读性。

三引号包围的字符串中,总是用双引号,以便和PEP 257的文档字符串(docstring)规则保持一致。

表达式和语句中的空格

招人烦

下列情形中避免用多余空格:

  • 方括号、圆括号和花括号在括号内紧挨着括号的部分:

    Yes:

    spam(ham[1], {eggs: 2})

    No:

    spam( ham[ 1 ], { eggs: 2 } )
  • 结尾处的逗号和紧挨着的的右括号之间:

    Yes:

    foo = (0,)

    No:

    bar = (0, )
  • 紧接着是逗号、分号或冒号:

    Yes:

    if x == 4: print x, y; x, y = y, x

    No:

    if x == 4 : print x , y ; x , y = y , x
  • 不过,切片操作中的冒号和二元操作符一样,应该在其左右两边保留相同数量的空格(就像其他低优先级的运算符一样)。在扩展切片操作中,所有冒号的左右两边空格数都应该相等。不过也有例外,当切片操作参数被省略时,应忽略空格。

    Yes:

    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]

    No:

    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]
  • 赋值(或其他)操作符周围,用多个空格和其他语句对齐:

    Yes:

    x = 1
    y = 2
    long_variable = 3

    No:

    x             = 1
    y             = 2
    long_variable = 3

其他建议

  • 行末不要加空白————又看不到,只会让人困惑:例如,后跟空格和换行符的反斜杠,不算作行延续标记。一些编辑器不会保留它们,许多项目(如CPython本身)会用预提交钩子(pre-commit hooks)干掉它们。
  • 二元操作符两边都加一个空格:赋值(=),增量赋值(+=, -= 等),比较(==, <, >, !=, <>, <=, >=, in, not in, is, is not),布尔(and, or, not)。
  • 如混合使用不同优先级的运算符,在优先级最低的操作符周围增加空白。可以自行判断;但,务必不要超过一个空格,务必保持二元操作符两侧空白一样多。

    Yes:

    i = i + 1
    submitted += 1
    x = x*2 - 1
    hypot2 = x*x + y*y
    c = (a+b) * (a-b)

    No:

    i=i+1
    submitted +=1
    x = x * 2 - 1
    hypot2 = x * x + y * y
    c = (a + b) * (a - b)
  • 函数注释应使用冒号的常规规则,在->箭头左右加上空格(如果要用的话)。(有关函数注释的更多信息,请参见下面的函数注释)

    Yes:

    def munge(input: AnyStr): ...
    def munge() -> AnyStr: ...

    No:

    def munge(input:AnyStr): ...
    def munge()->PosInt: ...
  • =表示关键字参数、或表示未注解(unannotated)函数参数的默认值时,不要在其左右加空格。

    Yes:

    def complex(real, imag=0.0):
        return magic(r=real, i=imag)

    No:

    def complex(real, imag = 0.0):
        return magic(r = real, i = imag)
  • 函数注解和参数默认值组合使用时(参数既有函数注解,又有默认值),在=两边各用一个空格:

    Yes:

    def munge(sep: AnyStr = None): ...
    def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...

    No:

    def munge(sep: AnyStr=None): ...
    def munge(input: AnyStr, sep: AnyStr=None, limit = 1000): ...
  • 复合语句(将多行语句写成一行)一般不鼓励使用。

    Yes:

    if foo == 'blah':
        do_blah_thing()
    do_one()
    do_two()
    do_three()

    Rather not:

    if foo == 'blah': do_blah_thing()
    do_one(); do_two(); do_three()
  • 有时,将短小的if/for/while中的语句写在一行是可以的,但对于多子句语句永远不要写成一行。也不要对这种长长的行换行续行处理!

    Rather not:

    if foo == 'blah': do_blah_thing()
    for x in lst: total += x
    while t < 10: t = delay()

    Definitely not:

    if foo == 'blah': do_blah_thing()
    else: do_non_blah_thing()
    
    try: something()
    finally: cleanup()
    
    do_one(); do_two(); do_three(long, argument,
                                 list, like, this)
    
    if foo == 'blah': one(); two(); three()

何时在末尾加逗号

末尾的逗号通常是可选的,只有在定义单元素元组(tuple)时是必需的(在Python 2中,具有print语句的语义)。为了更清楚,建议用括号(技术上是冗余的)括起来。

Yes:

FILES = ('setup.cfg',)

也还好, 但容易让人困惑:

FILES = 'setup.cfg',

虽然最后这个逗号是冗余的,但使用版本控制系统时,对于将来有可能扩充值、参数或import项目的列表来说,还是有好处的。具体来说,就是将每个元素单独写一行,行尾加逗号,最后的右括号单独占一行。但是,元素都在同一行上,末尾加逗号作为结束分隔符,是无意义的(除了上面单元素元组的情况)。

Yes:

FILES = [
    'setup.cfg',
    'tox.ini',
    ]
initialize(FILES,
           error=True,
           )

No:

FILES = ['setup.cfg', 'tox.ini',]
initialize(FILES, error=True,)

注释

和代码相冲突的注释,还不如没有注释。代码有变动,一定优先保证注释也同步变动!

注释应该用完整句子。第一个单词首字母要大写,除非是以小写字母开头的标识符(标识符千万不要改变大小写!)。

块注释通常由一个或多个由完整句子组成的段落构成,每个句子以句号结尾。

如果是多句注释,除最后一句,在句尾的句号后应使用两个空格。

如用英语书写,请参考Strunk和White的《The Elements of Style》。

对于非英语国家的Python程序员:请用英语写下注释,除非你有120%的把握不会给不懂你语言的人看。

块注释

块注释通常用于说明紧随其后的那些(或全部)代码,缩进级别和这些代码取齐。块注释的每一行,都以#和一个空格开始(除非文本是在注释内缩进对齐的)。

块注释里的段落,由只包含一个< code>#的行隔开。

行内注释

慎用行内注释。

行内注释与语句写在同一行。行内注释和语句之间至少用两个空格隔开。注释以#和一个空格开始。

行内注释并不必要,实际上,如果说明的是显而易见的事,反而会分散注意力。

不要这样做:

x = x + 1                 # x 自增

但有时,这样做是有意义的:

x = x + 1                 # 边界补偿

文档字符串

要写出好的文档字符串(docstrings),请参考PEP 257

  • 应该为所有公共模块、函数、类和方法编写文档字符串。对非公共方法,文档字符串不是必需的,但应该有注释来描述该方法的功能。此注释应出现在def定义行之后。
  • PEP 257 描述了好的文档字符串应遵循的规则。请注意,最重要的是,多行的文档字符串,应该用单独一行"""结尾,不能出现其他字符:

    """Return a foobang
    
    Optional plotz says to frobnicate the bizbaz first.
    """
  • 单行的文档字符串,请将"""加在同一行末尾。

命名约定

Python库的命名约定有点混乱,所以我们永远都无法做到真正的一致————不过,这里给出目前推荐的命名标准。新的模块和包(包括第三方框架)应该按这些标准编写,但如果现有库有不同风格,还是首先要和原有风格保持内部一致性。

首要原则

作为对用户可见的API公共部分的命名,首先应反映其用途,而不是其实现细节。

描述性:命名风格

有好几种不同的命名风格。最好是不论其用途、看名字能直接看出用的是什么命名风格。

命名风格常用区分如下:

  • b (单个小写字母)
  • B (单个大写字母)
  • lowercase(小写串)
  • lower_case_with_underscores(带下划线的小写串)
  • UPPERCASE(大写串)
  • UPPER_CASE_WITH_UNDERSCORES(带下划线的大写串)
  • CapitalizedWords (单词首字母大写串,也叫 CapWords, CamelCase5, StudlyCaps)
  • mixedCase (与单词首字母大写不同,第一个单词首字母是小写!)
  • Capitalized_Words_With_Underscores (难看!)
注意:

采用CapWords风格时,缩写单词的所有字母都要大写。HTTPServerError就比HttpServerError要好。

还有一种风格,是用一个短且唯一的前缀,将相关的名字组合在一起。这在Python中用得不多,为完整起见还是提一下。例如, os.stat() 函数返回一个元组,其中元素按传统命名为st_mode, st_size, st_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__ or __file__. 永远不要自己发明类似的名字;依文档描述使用。

说明性:命名约定

要避免的名称

永远不要用 ‘l’ (小写L), ‘O’ (大写O), 或 ‘I’ (大写I) 作为单字符变量名.

在某些字体中,这些字符与数字1、数字0几乎无法区分。想用“l”时,用“L”代替。

ASCII兼容性

标准库中用的标识符,必须与ASCII兼容,如PEP 3131policy部分所述。

包和模块的命名

模块应该有简短的、全小写的名称。为提高可读性,可在模块命名中用下划线。Python包命名也要用全小写的短名称,但不鼓提倡用下划线。

用C或C++写的扩展模块,如果有附带的Python模块提供更高级(例如,更面向对象)的接口时,C/C++模块名以下划线开头(例如 _socket)。

类的命名

类名通常应采用CapWords风格。

在接口有文档说明,且主要用作可调用接口时,可使用函数的命名约定。

注意,内置命名(builtin names)有一个特殊约定:大多数内置命名是单个单词(或两个单词连在一起),而CapWords约定仅用于异常命名和内置常量。

类型变量命名

PEP 484中引入的类型变量的命名,通常采用简短的CapWords命名约定:T, AnyStr, Num. 建议添加后缀 _co_contra 以声明协变(covariant)和逆变(contravariant)行为。

from typing import TypeVar

  VT_co = TypeVar('VT_co', covariant=True)
  KT_contra = TypeVar('KT_contra', contravariant=True)

异常命名

因为异常也是类,所以类命名约定在这里也适用。不过,应该给异常名加上“Error”后缀(如果异常实际上是个错误)。

全局变量的命名

(假定这些变量只能在同一个模块中使用)这些约定与函数的约定大致相同。

被设计通过 from M import * 方式使用的模块,应该用 __all__ 机制防止导出全局变量, 或者按老约定,在这些全局变量前加一个下划线(你可能想以此表明这些全局变量属于“模块非公开部分”)。

函数名和变量名

函数名应该小写,必要时用下划线分隔单词,以提高可读性。

变量名遵循与函数名相同的约定。

mixedCase只在以它为代码风格的上下文中使用(例如threading.py),以保持向后兼容性。

函数和方法参数

实例方法的第一个参数总是 self

类方法的第一个参数总是 cls

如果函数参数名与保留关键字冲突,最好加一个后置下划线,而不是用缩写或变体。class_ 就比 clss要好。(或许更好的做法是用同义词来避免冲突)

方法名和实例变量

根据需要,使用函数命名规则:小写,单词间用下划线分隔,以提高可读性。

仅在非公开方法和实例变量名字前加一个下划线。

为避免命名与子类冲突,用前置的双下划线来触发Python的命名修饰机制。

Python类名的命名修饰规则:如果Foo类有个名为 __a 的属性, 不能用 Foo.__a 访问到它. (坚持的用户仍然可以通过调用 Foo._Foo__a访问到它) 一般来说,前置双下划线的命名方法,仅用于避免与设计为子类的类中的属性名冲突。

注意: 关于 __names 的使用也有一些争议(如下)。

常量

常量通常在模块级定义,全部大写并用下划线分隔单词。 例如 MAX_OVERFLOWTOTAL.

继承的设计

总是想清楚,类方法和实例变量(统称为“属性”)应该是公开的还是非公开的。如果有疑问,就选择非公开;在之后,相比把公开属性变成非公开属性,把非公开属性变成公开属性要更容易些。

公开属性,是供那些和类设计无关的用户使用的属性,要确保其后续变更不会出现向后不兼容的问题。非公开属性,是那些你不打算让第三方使用的属性;无法确保非公开属性不被改动甚至删除。

在这里,我们不用“私有(private)”这个词,因为在Python中,没有什么属性是真正私有的(以节省往往不必要的额外工作)。

另一类属性,是那些属于“子类API”的属性(在其他语言也叫“受保护的(protected)”)。为扩展或修改类在某些方面的行为,我们会设计出一些继承自这些类的子类。设计这些子类时,要注意明确规划,哪些属性是公开的、哪些属性是子类API的一部分、哪些属性实际上仅供基类使用。

请把这几条放在心上,以下是Python风格的建议:

  • 公开属性名字前不要加下划线。
  • 如果公开属性名与保留关键字冲突,在属性名结尾加一个下划线,比用缩写或变体更好。(不过,尽管有这样的规则,但‘cls’仍然是所有已知为类的变量或参数的首选拼写,尤其是类方法的第一个参数)

    注1: 关于类方法,参考之前的参数命名建议。

  • 对于简单的公共数据属性,最好只公开属性名,而不要公开复杂的调用/设置方法。要是你发现哪个简单数据属性需要增加功能行为,记住,Python已经为将来的扩展提供了简单办法。用property注解,将功能实现隐藏在简单数据属性的访问语法背后。

    注1: property注解只对新风格的类有效

    注2: 尽量让功能行为无副作用,尽管像缓存之类的副作用也没什么大不了。

    注3: 对计算量大的操作,避免用property注解;属性符号会让调用者以为访问它运算量(相对)不大。

  • 如果类会被子类继承,而有些属性你不打算让子类用,可以考虑在命名时加前置双下划线、而不是后置下划线。这样会触发Python的命名修饰算法,将类名修饰添加到属性名。这样做,还能避免在子类无意间包含同名属性而引发命名冲突。

    注1: 注意,命名修饰只是简单地把类名加到修饰名中,如果子类同时有相同的类名和属性名,依然会引发命名冲突。

    注2: 命名修饰可能会让调试和__getattr__()等的使用变得不那么方便。不过,命名修饰算法有详尽的文档,手动实现也很容易。

    注3: 不是所有人都喜欢命名修饰。在避免意外命名冲突,和满足高级调用者的潜在用法之间,要尽量寻求平衡。

公开接口和内部接口

Any backwards compatibility guarantees apply only to public interfaces. Accordingly, it is important that users be able to clearly distinguish between public and internal interfaces.
所有向后兼容性保证,都仅限于公开接口。因此,让用户能清楚区分公开接口和内部接口非常重要。

Documented interfaces are considered public, unless the documentation explicitly declares them to be provisional or internal interfaces exempt from the usual backwards compatibility guarantees. All undocumented interfaces should be assumed to be internal.
写进文档里的接口,通常可理解为公开的,除非在文档里明确声明是临时的、或是不受向后兼容性保证约束的内部接口。所有没写进文档的接口,都被认为是内部接口。

To better support introspection, modules should explicitly declare the names in their public API using the __all__ attribute. Setting __all__ to an empty list indicates that the module has no public API.
为了更好地支持内省(introspection),模块应使用__all__属性,显式声明公开API有哪些命名。如__all__设为空列表,则表示该模块没有公开API。

Even with __all__ set appropriately, internal interfaces (packages, modules, classes, functions, attributes or other names) should still be prefixed with a single leading underscore.
即使设置了__all__,内部接口(包、模块、类、函数、属性及其他命名)仍应以一个下划线开头。

An interface is also considered internal if any containing namespace (package, module or class) is considered internal.
如果任何包含某接口的命名空间(包、模块或类)被认为是内部的,那么该接口也被认为是内部接口。

Imported names should always be considered an implementation detail. Other modules must not rely on indirect access to such imported names unless they are an explicitly documented part of the containing module’s API, such as os.path or a package’s __init__ module that exposes functionality from submodules.
import来的命名,应被视为实现细节。其他模块不得依赖对import命名的间接访问,除非文档明确说明它们是模块API的一部分,就像os.path、和从子模块开放内部功能的包的__init__模块一样。

编程建议

  • Code should be written in a way that does not disadvantage other implementations of Python (PyPy, Jython, IronPython, Cython, Psyco, and such).
    代码的编写,不应对其他版本的Python实现(PyPy、Jython、IronPython、Cyt hon、Psyco等)不利。

    For example, do not rely on CPython’s efficient implementation of in-place string concatenation for statements in the form a += b or a = a + b. This optimization is fragile even in CPython (it only works for some types) and isn’t present at all in implementations that don’t use refcounting. In performance sensitive parts of the library, the ''.join() form should be used instead. This will ensure that concatenation occurs in linear time across various implementations.
    例如,不要为了利用CPython的就地字符串连接高效实现,而采用a += ba = a + b这样的形式,即使在CPython中,这种优化也是脆弱的(只适用于某些类型),更不用说在其他没用引用计数器的实现中,根本没有这种优化。对库中性能敏感的部分,可采用''.join()的形式。这样可以确保在各种实现中,字符串拼接都能在线性时间内完成。

  • Comparisons to singletons like None should always be done with is or is not, never the equality operators.
    None 之类的单例(singleton)进行比较,应该总是用 isis not ,不要用==运算符。

    Also, beware of writing if x when you really mean if x is not None – e.g. when testing whether a variable or argument that defaults to None was set to some other value. The other value might have a type (such as a container) that could be false in a boolean context!
    另外,如果你实际要表达的是 if x is not None ,一定慎用 if x 这样的写法——例如,要检测默认值为 None 的变量或参数是否被设置成其他值。这个其他值可能是某种类型(如容器),该类型在布尔上下文中可能被当做False来处理!

  • Use is not operator rather than not ... is. While both expressions are functionally identical, the former is more readable and preferred.
    is not 操作符,不要用 not ... is。虽然两个表达式在功能上相同,但前者更可读,应作为首选。

    Yes:

    if foo is not None:

    No:

    if not foo is None:
  • When implementing ordering operations with rich comparisons, it is best to implement all six operations (__eq__, __ne__, __lt__, __le__, __gt__, __ge__) rather than relying on other code to only exercise a particular comparison.
    用富比较实现排序操作时,最好实现全部六个操作符(__eq__, __ne__, __lt__, __le__, __gt__, __ge__),而不是依靠另外的代码实现特定比较。

    To minimize the effort involved, the functools.total_ordering() decorator provides a tool to generate missing comparison methods.
    为最大限度减少工作量,functools.total_ordering() 装饰器提供了一个工具,会生成缺少的比较方法。

    PEP 207 indicates that reflexivity rules are assumed by Python. Thus, the interpreter may swap y > x with x < y, y >= x with x <= y, and may swap the arguments of x == y and x != y. The sort() and min() operations are guaranteed to use the < operator and the max() function uses the > operator. However, it is best to implement all six operations so that confusion doesn’t arise in other contexts.
    PEP 207 指明,Python会假定自反性是满足的,因此,解释器会把 y > x 转换成 x < y ,把 y >= x 转换成 x <= y ,对 x == yx != y 两边参数对换,sort()min() 操作保证会用 < 操作符,而 max() 函数则使用 > 操作符。无论如何,最好还是把所有六个操作都实现一下,以避免其他某些情况下出现混淆。

  • Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier.
    总是用def语句,而不是用赋值语句将lambda表达式直接绑定到标识符。

    Yes:

    def f(x): return 2*x

    No:

    f = lambda x: 2*x

    The first form means that the name of the resulting function object is specifically ‘f’ instead of the generic ‘<lambda>’. This is more useful for tracebacks and string representations in general. The use of the assignment statement eliminates the sole benefit a lambda expression can offer over an explicit def statement (i.e. that it can be embedded inside a larger expression)
    第一种形式,意味着生成的函数对象的名称是具体的“f”,而不是一般化的“& lt“lambda & gt”。一般来说,这样更利于回溯追踪(traceback)和字符串表示。赋值语句的使用,使得lambda表达式相较于显式def语句的唯一优势——可嵌入到更大的表达式———消失殆尽。

  • Derive exceptions from Exception rather than BaseException. Direct inheritance from BaseException is reserved for exceptions where catching them is almost always the wrong thing to do.
    Exception ,而不是 BaseException ,来派生出新的异常类。直接从 BaseException 继承,是为那些捕获几乎总是捕错了的异常而保留的。

    Design exception hierarchies based on the distinctions that code catching the exceptions is likely to need, rather than the locations where the exceptions are raised. Aim to answer the question “What went wrong?” programmatically, rather than only stating that “A problem occurred” (see PEP 3151 for an example of this lesson being learned for the builtin exception hierarchy)
    设计异常的层次结构,要基于能否用代码有效区分可能需要捕获的异常,而不是引发异常的位置。目标是通过编程回答“出了什么问题?”,而不仅仅是声明“这儿出了问题”(参见 PEP 3151 内建异常层次结构的例子)

    Class naming conventions apply here, although you should add the suffix “Error” to your exception classes if the exception is an error. Non-error exceptions that are used for non-local flow control or other forms of signaling need no special suffix.

  • Use exception chaining appropriately. In Python 3, “raise X from Y” should be used to indicate explicit replacement without losing the original traceback.
    异常链要使用得当。Python 3中,用 raise X from Y 来明确表示替换的同时不丢失原始回溯(信息和路径)。

    When deliberately replacing an inner exception (using “raise X” in Python 2 or “raise X from None” in Python 3.3+), ensure that relevant details are transferred to the new exception (such as preserving the attribute name when converting KeyError to AttributeError, or embedding the text of the original exception in the new exception message).
    当故意替换内部异常时(在Python 2中用 raise X 或在 Python 3.3+ 中用 raise X from None ),需确保相关细节能传递给新异常(例如,在将 KeyError 转换为 AttributeError 时保留属性名,或者在新的异常消息中嵌入原始异常文本)。

  • When raising an exception in Python 2, use raise ValueError('message') instead of the older form raise ValueError, 'message'.
    要在 Python 2 里抛出异常,用 raise ValueError('message') ,不要用旧式的 raise ValueError, 'message'

    The latter form is not legal Python 3 syntax.
    后一种形式,在 Python 3 语法中是非法的。

    The paren-using form also means that when the exception arguments are long or include string formatting, you don’t need to use line continuation characters thanks to the containing parentheses.
    采用圆括号形式抛出异常还意味着,当异常参数很长或包含字符串格式化时,得益于括号,将不必使用续行符。

  • When catching exceptions, mention specific exceptions whenever possible instead of using a bare except: clause.
    捕获异常时,尽可能明确指定具体异常,不要用空的 except: 子句。

    try:
        import platform_specific_module
    except ImportError:
        platform_specific_module = None

    A bare except: clause will catch SystemExit and KeyboardInterrupt exceptions, making it harder to interrupt a program with Control-C, and can disguise other problems. If you want to catch all exceptions that signal program errors, use except Exception: (bare except is equivalent to except BaseException:).
    空的 except: 子句,会捕获 SystemExit 和 KeyboardInterrupt 异常,这使得用 Control-C 中断程序变得更困难,还会掩盖其他问题。要捕获表示程序出错的所有异常,用 except Exception: (空异常相当于 except BaseException:)

    A good rule of thumb is to limit use of bare ‘except’ clauses to two cases:
    一条不错的经验法则——只在以下两种情况,才使用空的 except 子句:

    1. If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred.
      异常处理程序会打印或记录回溯信息;至少用户会意识到发生了错误。
    2. If the code needs to do some cleanup work, but then lets the exception propagate upwards with raise. try...finally can be a better way to handle this case.
      代码需要做一些清理工作,但之后会用 raise 向上抛出异常。这种情况用 try...finally 处理会更好。
  • When binding caught exceptions to a name, prefer the explicit name binding syntax added in Python 2.6:
    要想为捕捉到的异常绑定名称,最好用Python 2.6增加的显式命名绑定语法:

    try:
        process_data()
    except Exception as exc:
        raise DataProcessingFailedError(str(exc))

    This is the only syntax supported in Python 3, and avoids the ambiguity problems associated with the older comma-based syntax.
    Python 3只支持这种语法,避免了基于逗号的老式语法可能造成的歧义。

  • When catching operating system errors, prefer the explicit exception hierarchy introduced in Python 3.3 over introspection of errno values.
    捕捉操作系统错误时,最好用Python 3.3引入的显式异常层次结构,而不是 errno 值的内省。
  • Additionally, for all try/except clauses, limit the try clause to the absolute minimum amount of code necessary. Again, this avoids masking bugs.
    另外,对所有的 try/except 子句,将 try 子句限制为必需的最小范围代码。这样也可以避免掩盖错误。

    Yes:

    try:
        value = collection[key]
    except KeyError:
        return key_not_found(key)
    else:
        return handle_value(value)

    No:

    try:
        # Too broad!
        return handle_value(collection[key])
    except KeyError:
        # Will also catch KeyError raised by handle_value()
        return key_not_found(key)
  • When a resource is local to a particular section of code, use a with statement to ensure it is cleaned up promptly and reliably after use. A try/finally statement is also acceptable.
    当资源仅限于在特定代码段使用时,用 with 语句,以确保用完能迅速、可靠地清除。用 try/finally 语句也可以。
  • Context managers should be invoked through separate functions or methods whenever they do something other than acquire and release resources.
    但凡涉及到获取资源、释放资源以外的操作,上下文管理器都应该通过单独的函数或方法来调研。

    Yes:

    with conn.begin_transaction():
        do_stuff_in_transaction(conn)

    No:

    with conn:
        do_stuff_in_transaction(conn)

    The latter example doesn’t provide any information to indicate that the __enter__ and __exit__ methods are doing something other than closing the connection after a transaction. Being explicit is important in this case.
    第二个例子中,没提供任何信息能表明 __enter____exit__ 方法除了在事务完成后关闭连接以外,还做了什么。这种情况下,明确表达非常重要。

  • Be consistent in return statements. Either all return statements in a function should return an expression, or none of them should. If any return statement returns an expression, any return statements where no value is returned should explicitly state this as return None, and an explicit return statement should be present at the end of the function (if reachable).
    return 语句应保持一致:函数中所有 return 语句,要么都返回表达式,要么都不不返回。只要有一个 return 语句返回了表达式,所有不返回值的 return 语句都应明确声明为 return None,并在函数末尾明确加上 return 语句(如果能�������������������������行到的话)。

    Yes:

    def foo(x):
        if x >= 0:
            return math.sqrt(x)
        else:
            return None
    
    def bar(x):
        if x < 0:
            return None
        return math.sqrt(x)

    No:

    def foo(x):
        if x >= 0:
            return math.sqrt(x)
    
    def bar(x):
        if x < 0:
            return
        return math.sqrt(x)
  • Use string methods instead of the string module.使用字符串方法,而不是字符串模块。

    String methods are always much faster and share the same API with unicode strings. Override this rule if backward compatibility with Pythons older than 2.0 is required.
    字符串方法总是快得多,并且与unicode字符串有相同的API。如果需要跟2.0以前的Python向后兼容,可忽略此规则。

  • Use ''.startswith() and ''.endswith() instead of string slicing to check for prefixes or suffixes.
    ''.startswith()''.endswith() ,而不是字符串切片,来检查前缀或后缀。

    startswith() and endswith() are cleaner and less error prone.
    startswith()endswith() 更简洁,还不易出错

    Yes:

    if foo.startswith('bar'):

    No:

    if foo[:3] == 'bar':
  • Object type comparisons should always use isinstance() instead of comparing types directly:
    比较对象类型,应总是用 isinstance(),而不是直接比较类型:

    Yes:

    if isinstance(obj, int):

    No:

    if type(obj) is type(1):

    When checking if an object is a string, keep in mind that it might be a unicode string too! In Python 2, str and unicode have a common base class, basestring, so you can do:
    要检查对象是否是字符串,记住,它也可能是unicode字符串!在Python 2中,字符串和unicode有公共的基类basestring ,因此您可以:

    if isinstance(obj, basestring):

    Note that in Python 3, unicode and basestring no longer exist (there is only str) and a bytes object is no longer a kind of string (it is a sequence of integers instead)
    注意,在Python 3里,不再有 unicodebasestring (只有 str )),byte 对象也不再是字符串(而是整数序列)

  • For sequences, (strings, lists, tuples), use the fact that empty sequences are false:
    对序列(字符串、列表、元组)来说,利用空序列为 False 的事实:

    Yes:

    if not seq:
    if seq:

    No:

    if len(seq):
    if not len(seq):
  • Don’t write string literals that rely on significant trailing whitespace. Such trailing whitespace is visually indistinguishable and some editors (or more recently, reindent.py) will trim them.
    不要写依赖显著结尾空格的字符串。这种结尾空白在视觉上很难区分,还会被某些编辑器(包括最新的reindent.py)去掉。
  • Don’t compare boolean values to True or False using ==:
    不要用 == 比较布尔值和TrueFalse

    Yes:

    if greeting:

    No:

    if greeting == True:

    Worse:

    if greeting is True:

函数注解

With the acceptance of PEP 484, the style rules for function annotations are changing.
随着 PEP 484 被正式接受,函数注解的样式规则也发生了变化。

  • In order to be forward compatible, function annotations in Python 3 code should preferably use PEP 484 syntax. (There are some formatting recommendations for annotations in the previous section.)
    为了向前兼容,Python 3代码中的函数注解最采用 PEP 484 语法。(上一节有一些注解格式的建议。)
  • The experimentation with annotation styles that was recommended previously in this PEP is no longer encouraged.
    本PEP之前版本推荐的实验性注解风格不再建议使用。
  • However, outside the stdlib, experiments within the rules of PEP 484 are now encouraged. For example, marking up a large third party library or application with PEP 484 style type annotations, reviewing how easy it was to add those annotations, and observing whether their presence increases code understandability.
    不过,除stdlib外,鼓励在 PEP 484 规则范围内进行实验。例如,用 PEP 484 样式类型注解,标注大型第三方库或应用,评估添加这些注解是否方便,观察其存在对代码可理解性的影响。
  • The Python standard library should be conservative in adopting such annotations, but their use is allowed for new code and for big refactorings.
    Python标准库应谨慎采用此类注解,但要编写新代码、或进行大规模重构,还是可以用的。
  • For code that wants to make a different use of function annotations it is recommended to put a comment of the form:
    如果希望以其他方式使用函数注解,建议在文件头部添加以下形式的注释:

    # type: ignore

    near the top of the file; this tells type checker to ignore all annotations. (More fine-grained ways of disabling complaints from type checkers can be found in PEP 484.)
    通过这种方式告诉类型检查器,忽略所有注解。(可以在 PEP 484 中找到禁用类型检查程序报错的更细致的方法。

  • Like linters, type checkers are optional, separate tools. Python interpreters by default should not issue any messages due to type checking and should not alter their behavior based on annotations.
    和linters(静态代码分析工具)一样,类型检查器是可选的、单独的工具。默认情况下,Python解释器不应由于类型检查而发起消息,也不应由于注解改变其行为。

  • Users who don’t want to use type checkers are free to ignore them. However, it is expected that users of third party library packages may want to run type checkers over those packages. For this purpose PEP 484 recommends the use of stub files: .pyi files that are read by the type checker in preference of the corresponding .py files. Stub files can be distributed with a library, or separately (with the library author’s permission) through the typeshed repo 6.
    不想使用类型检查器的用户可以忽略它们。但第三方库包的用户,可能希望对这些包运行类型检查器。为此,PEP 484 建议使用.pyi存根文件,该.pyi文件由类型检查器先于相应的.py文件读取。存根文件可与库一起分发,也可(经库作者许可)通过typeshed repo6 单独分发。

  • For code that needs to be backwards compatible, type annotations can be added in the form of comments. See the relevant section of PEP 484 7.
    对需要向后兼容的代码,可以以注释形式添加类型注解。可参考 PEP 484 的相关章节7

变量注解

PEP 526 introduced variable annotations. The style recommendations for them are similar to those on function annotations described above:
PEP 526 引入了变量注释。它们的风格建议与上面描述的函数注解类似:

  • Annotations for module level variables, class and instance variables, and local variables should have a single space after the colon.
    模块级变量、类和实例变量以及局部变量的注解,在冒号后应有一个空格。
  • There should be no space before the colon.
    冒号前不要留空格。
  • If an assignment has a right hand side, then the equality sign should have exactly one space on both sides.
    如果赋值表达式右边有值,那么等号两边应该都有一个空格。
  • Yes:

    code: int
    
    class Point:
        coords: Tuple[int, int]
        label: str = '<unknown>'
  • No:

    code:int  # No space after colon(冒号后没空格)
    code : int  # Space before colon(冒号前有空格)
    
    class Test:
        result: int=0  # No spaces around equality sign(等号两边没空格)
  • Although the PEP 526 is accepted for Python 3.6, the variable annotation syntax is the preferred syntax for stub files on all versions of Python (see PEP 484 for details).
    尽管 PEP 526 被 Python 3.6 采纳,变量注解语法,仍是所有Python版本存根文件的首选语法。(详情可参考 PEP 484)

脚注

  1. PEP 7, Style Guide for C Code, van Rossum

  2. Barry’s GNU Mailman style guide http://barry.warsaw.us/software/STYLEGUIDE.txt

  3. Hanging indentation is a type-setting style where all the lines in a paragraph are indented except the first line. In the context of Python, the term is used to describe a style where the opening parenthesis of a parenthesized statement is the last non-whitespace character of the line, with subsequent lines being indented until the closing parenthesis.
    悬挂缩进是一种排版样式,段落中除第一行以外所有行都缩进。在Python中,该术语用于描述一种样式,其中带括号语句的左括号是该行的最后一个非空白字符,随后的行缩进直到右括号。

  4. Donald Knuth's The TeXBook, pages 195 and 196.

  5. http://www.wikipedia.com/wiki/CamelCase

  6. Typeshed repo https://github.com/python/typeshed

  7. Suggested syntax for Python 2.7 and straddling code https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code

This document has been placed in the public domain.

Fork me on GitHub