代码书写规范不仅能够使自己二次阅读自己的代码时快速上手,也方便其他人阅读和理解,我们应当尽量遵守统一的约定,下面摘录了PEP8 中的部分代码规范样式,供大家参考。
代码布局缩进制表符还是空格?代码行最大长度换行符应该在二元运算符之前还是之后?空行源文件编码导入模块模块级Dunder名称字符串引号表达式和语句中的空白忌讳其他建议什么时候使用结尾逗号?注释块注释内镶注释文档字符串命名约定首要原则描述性:命名样式说明性:命名约定避免使用的名称ASCII兼容性软件包和模块名称类名类型变量名异常名称全局变量名函数和变量名函数和方法参数方法名称和实例变量常量继承设计
每个缩进级别使用4个空格。
续行应使用在括号,方括号和花括号内使用Python的隐式线垂直对齐包装的元素,或使用悬挂式缩进 。使用悬挂式缩进时,应考虑以下几点:
第一行上不应有任何参数,应使用进一步的缩进以将自己清楚地区分为延续行。
正确写法:
# 对齐分隔符.
foo = long_function_name(var_one, var_two,
var_three, var_four)
# 添加4个空格(额外的缩进级别)以区分参数和其他部分(8个空格,而不是4个).
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)
错误写法:
# 不使用垂直对齐时,禁止在首行使用参数.
foo = long_function_name(var_one, var_two,
var_three, var_four)
# 由于缩进无法区分,需要更多的缩进来区分(8个空格,而不是4个).
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
对于连续行,4个空格的规则是可选的。 可选的:
# 悬挂缩进可以使用除4个空格以外的其他个数空格.
foo = long_function_name(
var_one, var_two,
var_three, var_four)
当if
语句过长而需要写成多行时,应该注意到if
语句的换行会产生4个空格的缩进,这与嵌套在if
语句内部的代码集缩进会形成视觉冲突,该缩进代码也是4个空格。对于如何在视觉上进一步将这些条件行与 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()
多行构造的 { } / [ ] / ( )
可以在列表最后一行的第一个非空白字符下对齐,如下所示:
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',
)
空格是首选的缩进方法。
制表符应仅用于与已经用制表符缩进的代码保持一致。
Python 3不允许混合使用制表符和空格进行缩进。
由制表符和空格组成的缩进的Python 2代码应转换为仅使用空格。
当使用-t选项调用Python 2命令行解释器时,它会发出有关非法混用制表符和空格的代码的警告。当使用-tt时,这些警告变为错误。强烈建议您使用这些选项!
限制所有行最多79个字符。
为了使较长的文本块具有较少的结构限制(文档字符串或注释),行长应限制为72个字符。
通过限制编辑器窗口宽度,可以并排打开多个文件,并且在使用在相邻列中显示两个版本的代码查看工具时效果很好。
Python标准库是保守的,需要将行数限制为79个字符(文档字符串/注释数限制为72个)。
包装长行的首选方法是在括号,方括号和花括号内使用Python的隐含行连续性。通过将表达式包装在括号中,可以将长行分成多行。应优先使用这些,而不是使用反斜杠进行行连续。
有时反斜杠可能仍然合适。例如,很长的、多重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())
几十年来,推荐的样式是在二元运算符之后使用。但这会以两种方式损害可读性:运算符趋向于分散在屏幕的不同列上,并且,每个运算符都将运算对象移至前一行。在这里,眼睛必须做额外的工作才能分辨出哪些项目被添加、哪些项目被减去了:
# No: 操作符的位置远离操作对象
income = (gross_wages +
taxable_interest +
(dividends - qualified_dividends) -
ira_deduction -
student_loan_interest)
为了解决这个可读性问题,数学家及其出版物遵循相反的约定。Donald Knuth在他的 “ *计算机和排版 ” *系列中解释了这种惯例规则:“尽管段落中的公式总是在二元运算和关系之后中断,显示的公式却总是在二元运算之前中断” 。 遵循数学的惯例传统通常会写出更具有可读性的代码:
# Yes: 很方便的匹配运算符和运算对象。
income = (gross_wages
+ taxable_interest
+ (dividends - qualified_dividends)
- ira_deduction
- student_loan_interest)
在Python代码中,只要约定与本地是一致的,就可以在二元运算符之前或之后中断。对于新代码,建议使用数学家 Knuth
的样式。
用两个空行环绕顶级函数和类定义。
类内部的方法定义由单个空白行环绕。
额外的空白行可以用于分隔相关的功能组。一堆相关的单线之间可以省略空白行。
在函数中使用空白行,占用很少的空间,以指示逻辑部分。
Python接受control-L(即^ L)换页符作为空格;许多工具将这些字符视为页面分隔符,因此你可以使用它们来分隔文件相关部分的页面。请注意,某些编辑器和基于Web的代码查看器可能无法将Control-L识别为换页符,而将在其位置显示另一个标志符号。
核心Python发行版中的代码应始终使用UTF-8(或Python 2中的ASCII)。
使用ASCII(在Python 2中)或UTF-8(在Python 3中)的文件不应具有编码声明。
在标准库中,非默认编码仅应用于测试目的,或者在注释或文档字符串需要提及包含非ASCII字符的作者姓名时;否则,使用 \ x, \ u,\ U
或 \ N
转义是在字符串文字中包含非ASCII数据的首选方法。
对于Python 3.0及更高版本,标准库规定了以下策略:Python标准库中的所有标识符务必使用纯ASCII标识符,并且在可行的情况下应使用英文单词(在许多情况下,缩写和技术使用非英语的术语)。此外,字符串文字和注释也必须使用ASCII。唯一的例外是(a)测试非ASCII功能的测试用例,以及(b)作者的姓名。名称不基于拉丁字母(latin-1,ISO / IEC 8859-1字符集)的作者必须在此字符集中提供其姓名的音译。
鼓励具有全球受众的开源项目采用类似的策略。
导入通常应在单独的行上:
Yes: import os
import sys
No: import sys, os
可以这样说:
from subprocess import Popen, PIPE
导入总是放在文件的顶部,紧随任何模块注释和文档字符串之后,以及模块全局变量和常量之前。 导入应按如下顺序分组:
你应该在每组导入之间放置一个空白行。
推荐绝对导入,因为如果导入系统配置不正确(例如,程序包中的目录最终位于sys.path时),则它们通常更具可读性,并且通常表现更好(或至少会提供更好的错误消息):
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example
但是,显式相对导入是绝对导入的一种可接受的替代方法,特别是在处理复杂的包装布局时,使用绝对导入会不必要地冗长:
from . import sibling
from .sibling import example
from myclass import MyClass
from foo.bar.yourclass import YourClass
如果此拼写引起本地名称冲突,则应明确拼写它们:
import myclass
import foo.bar.yourclass
并使用“ myclass.MyClass”和“ foo.bar.yourclass.YourClass”。
应避免使用通配符导入( from <module> import *
),因为通配符使名称空间中不清楚存在哪些名称,这会混淆读取器和许多自动化工具。通配符导入有一个合理的用例,它是将内部接口重新发布为公共API的一部分(例如,重写可选的加速器模块的纯Python实现,被重写的定义是事先未知的)。
以这种方式重新发布名称时,有关公共和内部接口的准则仍然适用。
模块级“dunders”(即名称前后具有两个下划线)如all__,_author_,__version等,应被放置在模块文档字符串之后,但在除 from __future__ imports
之外的导入语句之前。Python要求将来的导入必须出现在模块中的除文档字符串以外的任何其他代码之前:
"""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
推荐写法:
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 = 1
y = 2
long_variable = 3
不推荐写法:
x = 1
y = 2
long_variable = 3
=
,扩展赋值运算符 +=, -= 等
,比较运算符 ==, <, >, !=, <>, <=, >=, in, not in, is, is not
,布尔运算符 and, or, not
。推荐写法:
i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
不推荐写法:
i=i+1
submitted +=1
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a + b) * (a - b)
->
运算符,请在其前后各使用一个空格。推荐写法:
def munge(input: AnyStr): ...
def munge() -> AnyStr: ...
不推荐写法:
def munge(input:AnyStr): ...
def munge()->PosInt: ...
=
前后使用空格。推荐写法:
def complex(real, imag=0.0):
return magic(r=real, i=imag)
不推荐写法:
def complex(real, imag = 0.0):
return magic(r = real, i = imag)
=
前后使用空格。推荐写法:
def munge(sep: AnyStr = None): ...
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...
不推荐写法:
def munge(input: AnyStr=None): ...
def munge(input: AnyStr, limit = 1000): ...
推荐写法:
if foo == 'blah':
do_blah_thing()
do_one()
do_two()
do_three()
而不是:
if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()
虽然有时可以将 if / for / while
的小主体放在同一行上,但对于多子句语句则永远不要这样做。也要避免折叠这么长的行!
而不是:
if foo == 'blah': do_blah_thing()
for x in lst: total += x
while t < 10: t = delay()
当然不:
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()
尾部的逗号通常是可选的,但是,组成一个元素的元组时,它是必需的(并且在Python 2中,它们具有print语句的语义)。为了清楚起见,建议将后者用(技术上多余的)括号括起来。
因python官方停止维护python2,本文后期忽略所有python2内容部分
就像这样:
FILES = ('setup.cfg',)
可以,但是,让人费解的写法:
FILES = 'setup.cfg',
通常来说,结尾的逗号多余,但是在使用版本控制系统时,它们通常会很有用。此时,参数值,参数或导入项的列表预计会随着时间扩展。模式是将每个参数或值(等)单独放在一行上,始终添加尾随逗号,并在下一行上添加右括号/括号/括号。但是,在与结束定界符相同的行上使用尾随逗号是没有意义的(在上述单例元组的情况下除外)。 类似这样:
FILES = [
'setup.cfg',
'tox.ini',
]
initialize(FILES,
error=True,
)
这样是不可取的:
FILES = ['setup.cfg', 'tox.ini',]
initialize(FILES, error=True,)
与代码矛盾的注释比没有注释更糟糕。当代码更改时,始终优先考虑更新注释!
注释应该是完整的句子。第一个单词应大写,除非它是一个以小写字母开头的标识符(请勿更改标识符的大小写!)。
块注释通常由一个或多个完整句子组成的段落组成,每个句子以句点结尾。
在多句注释中,除了最后一句之后,您应该在句子结尾句后使用两个空格。
编写英语时,请遵循Strunk and White。
来自非英语国家的Python编码人员:请用英语写您的注释,除非您有120%的把握确保不会说这种语言的人不会阅读该代码。
块注释通常用于注解位于一些(或全部)代码之前,并且缩进到与该代码相同的级别。块注释的每一行都以#和一个空格开头(除非注释中的文本是缩进的)。
块注释中的段落由包含单个#的行分隔。
请谨慎使用内镶注释。
内镶注释是与语句在同一行上的注释。内联注释应与语句至少分隔两个空格。它们应以#和单个空格开头。
内镶注释不是必须的,事实上,如果它的注解是显而易见的,实际上会分散注意力。不要这样做:
x = x + 1 # Increment x
但是有些时候,他很有用:
x = x + 1 # Compensate for border
在PEP 257中,编写好的文档字符串(也称为“文档字符串”)的约定永垂不朽。
"""Return a foobang
Optional plotz says to frobnicate the bizbaz first.
"""
Python库的命名约定有点混乱,因此我们永远都无法做到完全一致。尽管如此,如下是当前推荐的命名标准。新的模块和软件包(包括第三方框架)应按照这些标准编写,但是如果现有库具有不同的样式,则首选内部一致性。
对于用户而言,作为API公共部分可见的名称应遵循反映用法而不是实现的约定。
有很多不同的命名样式。能够独立于它们的用途来识别正在使用的命名样式。
通常区分以下命名样式:
还有一种使用短的唯一前缀将相关名称组合在一起的样式。这在Python中使用不多,但出于完整性的考虑而提及。例如,os.stat()函数返回一个元组,该元组的项目传统上具有诸如st_mode, st_size,st_mtime等名称。(这样做是为了强调与POSIX系统调用结构的字段的对应关系,这有助于程序员熟悉该结构。)
X11 库将前导 X 用于其所有公共功能。在Python中,这种样式通常被认为是不必要的,因为属性和方法名称以对象为前缀,函数名称以模块名作为前缀。
此外,以下使用前划线或后划线的特殊形式也是公认的(通常可以将它们与任何大小写惯例结合使用):
Tkinter.Toplevel(master, class_='ClassName')
切勿将字符“ l”(小写字母el),“ O”(大写字母oh)或“ I”(大写字母eye)用作单个字符变量名称。
在某些字体中,这些字符与数字1和零没有区别。当尝试使用“ l”时,请改用“ L”。
标准库中使用的标识符必须与PEP 3131的策略部分中所述的ASCII兼容 。
Modules 应使用简短的全小写名称。如果模块名称可以提高可读性,则可以在模块名称中使用下划线。尽管不鼓励使用下划线,但Python packages 也应使用短的全小写名称。
当用C或C ++编写的扩展模块具有随附的Python模块提供更高级别(例如,面向对象)的接口时,C / C ++模块具有一个下划线(例如_socket)。
类名通常应使用CapWords约定。
在接口被记录并主要用作可调用函数的情况下,可以代替使用函数的命名约定。
请注意,内置名称有一个单独的约定:大多数内置名称是单个单词(或两个单词一起运行),而CapWords约定仅用于异常名称和内置常量。
在PEP 484中引入的类型变量的名称通常应使用CapWords,而应使用短名称:T,AnyStr,Num。建议将后缀_co或_contra分别添加到用于声明协变或相反行为的变量中:
from typing import TypeVar
VT_co = TypeVar('VT_co', covariant=True)
KT_contra = TypeVar('KT_contra', contravariant=True)
因为异常应该是类,所以此处使用类命名约定。但是,您应该在异常名称上使用后缀“ Error”(如果异常实际上是一个错误)。
(我们希望这些变量只能在一个模块内使用。)约定与函数的约定大致相同。
设计用于 from M import * 使用的模块应使用 all 机制以防止导出全局变量,或使用较早的约定在此类全局变量前加下划线(您可能需要这样做以表明这些全局变量是“非公开模块” ”)。
函数名称应小写,必要时用下划线分隔单词,以提高可读性。
变量名与函数名遵循相同的约定。
仅在已经是主流样式(例如threading.py)的上下文中才允许使用mixedCase,以保持向后兼容性。
始终将 self 作为实例方法的第一个参数。
始终对类方法的第一个参数使用 cls 。
如果函数参数的名称与保留关键字发生冲突,通常最好在末尾附加一个下划线,而不要使用缩写或拼写错误。因此,class_优于clss。(也许最好通过使用同义词来避免此类冲突。)
使用函数命名规则:小写字母,必要时用下划线分隔单词,以提高可读性。
仅对非公开方法和实例变量使用前导下划线。
为避免名称与子类冲突,请使用两个前导下划线来调用Python的名称处理规则。
Python用类名来修饰这些名称:如果类Foo具有名为 __a
的属性,则 Foo .__a
不能访问它。(坚持的用户仍然可以通过调用 Foo._Foo__a
来获得访问权限。)通常,双引号下划线仅应用于避免名称与设计为子类的类中的属性发生冲突。
注意:关于 __name
的使用存在一些争议(请参见下文)。
常量通常在模块级别定义,并以所有字母大写书写,并用下划线分隔单词。示例包括 MAX_OVERFLOW和TOTAL。
始终确定类的方法和实例变量(统称为“属性”)应该是公共的还是非公开的。如有疑问,请选择非公开;后期将其变为公共属性比将公共属性变为非公开属性要容易。
公共属性是您期望类中不相关的客户端使用的属性,并承诺避免向后不兼容的更改。非公开属性是指不打算由第三方使用的属性;您不保证非公开属性不会更改甚至被删除。
我们在此不使用术语“私有”,因为在Python中没有任何属性是真正私有的(通常没有不必要的工作量)。
另一类属性是属于“子类API”(在其他语言中通常称为“受保护”)的那些属性。某些类被设计为可以继承或扩展或修改类行为的各个方面。在设计此类时,请务必明确决定哪些属性是公共属性,哪些是子类API的一部分,哪些属性仅由基类真正使用。
考虑到这一点,以下是Python准则:
公共属性不应有前导下划线。
如果您的公共属性名称与保留关键字冲突,请在属性名称后附加一个下划线。这比缩写或拼写错误更可取。(但是,尽管有此规则,对于任何已知的类的变量或参数,尤其是类方法的第一个参数,“ cls”是首选的拼写。)
注1:有关类方法,请参见上面的参数名称建议。
对于简单的公共数据属性,最好仅公开属性名称,而不使用复杂的访问器/更改器方法。请记住,Python为未来的增强提供了简便的方法,您应该发现需要一个简单的数据属性来实现功能增强行为。在这种情况下,使用属性将功能实现隐藏在简单的数据属性访问语法之后。
注1:属性仅适用于新型类。
注2:尽管一般来说,诸如缓存之类的副作用都不错,但是请尽量使功能行为没有副作用。
注3:避免将属性用于计算昂贵的操作;属性表示法使调用者认为访问(相对)便宜。
如果您的类打算被子类化,并且您具有不希望子类使用的属性,请考虑使用双下划线开头并且没有下划线结尾的样式来命名它们。这将调用Python的名称修改算法,其中将类的名称修改为属性名称。如果子类无意中包含相同名称的属性,这有助于避免属性名称冲突。
注1:请注意,整齐的名称中仅使用简单的类名,因此,如果子类同时选择了相同的类名和属性名,则仍会发生名称冲突。
注2:名称修饰可以有某些用途(例如调试和 __getattr__
),就是不太方便。但是,名称处理算法已被详细记录,并且易于手动执行。
注3:并非每个人都喜欢名称修饰。尝试在避免意外名称冲突和上层调用可能使用名称之间取得平衡。