点赞再看,养成习惯!觉得不过瘾的童鞋,欢迎关注公众号《机器学习算法工程师》,有非常多大神的干货文章可供学习噢…
最近小编在学习requests源码时遇到了不少pythonic代码,十分精妙,实在欢喜得很,于是便产生了想系统学习下py代码规范的念头,这便是这篇文章的由来。闲话少叙,上干货吧^ - ^
本文档给出了构成主要Python发行版中标准库的Python代码的编码约定。关于Python[1]的C实现中的C代码,请参阅相应的信息性PEP描述风格指南。
本文和 PEP 257(Docstring Conventions)改编自Guido的原始Python风格指南文章,并从Barry的风格指南[2]中添加了一些内容。
这个风格指南会随着时间的推移而发展,会出现新的约定并且过去的约定会因为语言本身的变化而过时。
许多项目都有自己的编码风格指南。在任何冲突的情况下,这种特定于项目的指南对于该项目而言应该优先考虑。
Guido的一个关键见解是,阅读代码的次数比编写代码的次数要多。这里提供的指导方针旨在提高代码的可读性,并使其在各种Python代码中保持一致。正如PEP 20所说,“可读性很重要”。
风格指南是关于一致性的。与这个风格指南保持一致非常重要。项目内部的一致性更为重要。在一个模块或函数的一致性是最重要的。
但是,要知道什么时候不一致——有时候风格指南的建议并不适用。当你有疑问的时候,相信自己。看看其他的例子并决定采取哪种方案。不要害怕问问题!
特别是:不要强行为了与这个PEP保持一致而破坏向后兼容性(backwards compatibility)!
能够忽视指定的指南的一些其他理由有:
使用4个空格缩进。
连续行应该使用Python的隐式行连接括号、方括号和大括号,或者使用悬挂缩进[7]对包装的元素进行垂直对齐。在使用悬挂缩进时,应考虑以下因素;在第一行应该没有参数,进一步的缩进应该被用来清楚地区分自己是一个延续行:
# Correct:
# Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
var_three, var_four)
# Add 4 spaces (an extra level of indentation) to distinguish arguments 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)
# Wrong:
# 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语句(if-statement)的条件部分太长了以致于需要跨多行写时,值得注意的是,if加上一个空格还有(,创建一个后续多行都是4空格缩进的条件。这可能会与嵌套在if语句中的代码集产生视觉冲突,因为该代码集也是缩进4个空格。对于这种情况如何区分,PEP不采取明确的立场。在这种情况下可以接受的选项包括但不限于:
# 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()
(也可参考下面关于是否在二元操作符binary operators之前或之后断开的讨论。)
在多行结构中,匹配的右括号可以在列表最后一行的第一个非空白字符下面,如:
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个字符。
限制所需的编辑器窗口宽度可以让几个文件并肩打开,并且当使用以相邻列显示两个版本的代码审查工具时能工作得很好。
大多数工具中的默认wrap破坏了代码的可视化结构,使其更加难以理解。选择这些限制是为了避免在窗口宽度设置为80的编辑器中换行,即使在换行时工具在最后一列中放置了标记符号。一些基于web的工具可能不提供动态wrap。
有些团队更喜欢长行。对于这些团队维护的代码,可以将行长度限制增加到99个字符,前提是注释和文档字符串仍然wrap为72个字符。
Python标准库比较保守,要求每行限制在79个字符(文档字符串/注释限制在72个字符)。
wrap长行推荐的方法是在括号内使用Python的隐式行延续。通过将表达式wrap在括号中,可以将长行拆分为多行。相比使用反斜杠来做到行延续,这个方法更值得采用。
有时反斜杠仍然是合适的。例如,长并且多个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())
(关于多行if语句的缩进,请参考前面关于多行with语句的讨论。)
另一种情况是assert语句。
确保适当地缩进延续行。
几十年来,推荐的风格是在二元操作符之后断开。但是这可能在两个方面降低可读性:操作符往往分散在屏幕上的不同列,每个操作符都从它的操作数移到前一行。这样一来给眼睛增加了负担,来区分哪些项目是增加的,哪些是减少的:
# Wrong:
# operators sit far away from their operands
income = (gross_wages +
taxable_interest +
(dividends - qualified_dividends) -
ira_deduction -
student_loan_interest)
为了解决这个可读性问题,数学家和他们的出版商遵循相反的惯例。Donald Knuth在他的计算机和排版系列中解释了这个传统规则:“虽然一个段落中的公式总是在二元操作和关系之后断开,但显示的公式总是在二元操作之前断开”[3]。
遵循数学惯例通常导致更易读的代码:
# Correct:
# easy to match operators with operands
income = (gross_wages
+ taxable_interest
+ (dividends - qualified_dividends)
- ira_deduction
- student_loan_interest)
在Python代码中,允许在二元操作符之前或之后断开,只要局部保持一致即可。对于新代码,建议使用Knuth的风格。
最外层函数和类定义之间用两个空行分开。
类内的方法之间用一个空行分开。
可以(有节制地)使用额外的空行来分隔一组相关函数。在一组相关行(例如一组dummy implementations)之间可以省略空行。
在函数中适当地使用空行来分开不同的逻辑内容。
Python接受control-L(即^L)形式的feed字符作为空格;许多工具将这些字符作为页面分隔符,因此可以使用它们来分隔文件相关部分的页面。请注意,一些编辑器和基于web的代码查看器可能不会将control-L识别为form feed,并将在其位置显示另一个符号。
核心Python发行版中的代码应该始终使用UTF-8(或Python 2中的ASCII)。
使用ASCII(在python2中)或UTF-8(在python3中)的文件不应该有编码声明。
在标准库中,非默认编码只能用于测试目的,或者当注释或文档字符串需要提到包含非ASCII字符的作者名字时;否则,使用\x、\u、\u或\N转义是在字符串文本中包含非ascii数据的首选方法。
对于Python 3.0及以后版本,标准库制定了以下策略(请参考PEP 3131): Python标准库中的所有标识符必须使用ASCII的标识符,并且应该在可行的情况下使用英语单词(在许多情况下,使用的是非英语的缩写和技术术语)。此外,字符串常量和注释也必须是ASCII格式的。唯一可以例外的是(a)测试非ASCII特性的测试用例,和(b)作者的名字。名字不是基于拉丁字母(Latin -1, ISO/IEC 8859-1字符集)的作者必须提供其名称在该字符集中的音译。
鼓励面向全球用户的开放源码项目采用类似的策略。
导入通常应该单独一行:
# Correct:
import os
import sys
# Wrong:
import sys, os
这样的可以:
# Correct:
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
标准库代码应该避免复杂的包布局,并始终使用绝对路径导入。
隐式相对路径导入永远不应该使用,并且已经在Python 3中删除了。
当从包含类的模块中导入类时,通常可以拼写为:
from myclass import MyClass
from foo.bar.yourclass import YourClass
如果这种拼写导致本地名称冲突,则显式拼写:
import myclass
import foo.bar.yourclass
使用"myclass.MyClass" 和"foo.bar.yourclass.YourClass"。
应该避免使用通配符导入 (from
当以这种方式重新发布名称时,下面有关公共接口和内部接口的指导原则仍然适用。
模块级别的“dunders”(即在前面和后面都带有两个下划线的命名),如__all__, __author__, __version__等,应该放置在模块的文档字符串后面但要在任何导入语句(除了__future__导入)前面。Python规定future导入位置必须出现在模块中除文档字符串之外的任何其他代码之前:
"""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约定一致。
在下列情况下避免不必要的空格:
紧贴括号:
# Correct:
spam(ham[1], {eggs: 2})
# Wrong:
spam( ham[ 1 ], { eggs: 2 } )
在后逗号和后括号之间:
# Correct:
foo = (0,)
# Wrong:
bar = (0, )
紧接在逗号、分号或冒号前面的:
# Correct:
if x == 4: print x, y; x, y = y, x
# Wrong:
if x == 4 : print x , y ; x , y = y , x
但是,在切片中,冒号的作用类似于二元运算符,并且应该在每一边都有相等的数量(将其视为优先级最低的运算符)。在扩展切片中,两个冒号应用的间距必须相同。例外:当切片参数被省略时,空间被省略:
# Correct:
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]
# Wrong:
ham[lower + offset:upper + offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : upper]
ham[ : upper]
在函数调用参数列表开始的左括号之前:
# Correct:
spam(1)
# Wrong:
spam (1)
紧接开始索引或切片的左括号之前:
# Correct:
dct['key'] = lst[index]
# Wrong:
dct ['key'] = lst [index]
赋值(或其他)操作符周围的多个空格,使其与其他操作符对齐:
# Correct:
x = 1
y = 2
long_variable = 3
# Wrong:
x = 1
y = 2
long_variable = 3
避免尾随空格。因为它通常是不可见的,所以它可能会让人感到困惑:例如,反斜杠后面跟着空格和换行符不被视为行继续标记。有些编辑器不保存它并且许多项目(比如CPython本身)都有拒绝这种空格的pre-commit hooks。
始终在这些二元操作符的两边用一个空格包围:赋值(=)、扩展赋值(+=,-=等)、比较(==,<, >, !=, <> , <=, >=, in, not in, is, is not)、布尔值(and, or, not)。
如果使用具有不同优先级的操作符,请考虑在优先级最低的操作符周围添加空格。相信自己的判断;但是,使用空格的地方只用一个空格,并且在二元操作符的两边要有相同数量的空格:
# Correct:
i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
# Wrong:
i=i+1
submitted +=1
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a + b) * (a - b)
函数注释(Function annotations)应使用冒号的常规规则,并且如果存在,则->箭头周围始终有空格。 (关于功能注释的更多信息,下面章节会讲到。):
# Correct:
def munge(input: AnyStr): ...
def munge() -> PosInt: ...
# Wrong:
def munge(input:AnyStr): ...
def munge()->PosInt: ...
当用于指示关键字参数或用于指示未注释的函数参数的默认值时,请勿在=符号周围使用空格:
# Correct:
def complex(real, imag=0.0):
return magic(r=real, i=imag)
# Wrong:
def complex(real, imag = 0.0):
return magic(r = real, i = imag)
但是,当将参数注释与默认值组合时,请在=符号周围使用空格:
# Correct:
def munge(sep: AnyStr = None): ...
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...
# Wrong:
def munge(input: AnyStr=None): ...
def munge(input: AnyStr, limit = 1000): ...
通常不建议使用复合语句(同一行上的多个语句):
# Correct:
if foo == 'blah':
do_blah_thing()
do_one()
do_two()
do_three()
而不是:
# Wrong:
if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()
尽管有时可以将比较小的if / for / while的主体放在同一行上,但是对于多子句的语句则永远不要这样做。也要避免折叠这么长的行!
别这样:
# Wrong:
if foo == 'blah': do_blah_thing()
for x in lst: total += x
while t < 10: t = delay()
也不要这样:
# Wrong:
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语句的语义)。 为了清楚起见,建议后者将逗号用(技术上多余的)括号括起来:
# Correct:
FILES = ('setup.cfg',)
# Wrong:
FILES = 'setup.cfg',
如果结尾的逗号多余,则在使用版本控制系统时,当存放值,参数或导入项的列表预计会随着时间扩展时,它们通常会很有用。这种模式是指将每个值单独放在一行上,始终添加尾随逗号,并在下一行上添加右括号。但是,在与结束定界符相同的行上加上逗号是没有意义的(在上述单例元组的情况下除外):
# Correct:
FILES = [
'setup.cfg',
'tox.ini',
]
initialize(FILES,
error=True,
)
# Wrong:
FILES = ['setup.cfg', 'tox.ini',]
initialize(FILES, error=True,)
与代码矛盾的注释比没有注释更糟糕。当代码更改时,记住一定要第一时间更新注释!
注释应为完整句子。第一个单词应大写,除非它是一个以小写字母开头的标识符(请勿更改标识符的大小写!)。
整体注释通常由一个或多个完整句子组成的段落组成,每个句子以句点结尾。
在多句注释中,除了最后一句,您应该在每个句子结尾使用两个空格。
确保您的注释清晰明了,并且其他母语使用者也很容易理解。
来自非英语国家的Python编码人员:请用英语写您的注释,除非您有120%的把握确保只会有会说您的母语的人阅读该代码。
块注释通常适用于其后的某些(或全部)代码,并且缩进到与该代码相同的级别。块注释的每一行都以#和一个空格开头(除非注释内的文本是缩进的)。
块注释中的段落由包含单个#的行分隔。
谨慎使用行内注释。
行内注释是与语句在同一行上的注释。行内注释应与语句至少分隔两个空格。它们应以#和单个空格开头。
行内注释是不必要的,并且如果该行代码的意思显而易见,那么用了行内注释实际上会分散注意力。不要这样做:
x = x + 1 # Increment x
但是有时候,这很有用:
x = x + 1 # Compensate for border
在PEP 257中,指示了良好文档字符串的规范。
为所有公共模块,函数,类和方法编写文档字符串。对于非公共方法,文档字符串不是必需的,但是您应该具有描述该方法功能的注释。该注释应出现在def行之后。
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”。
标准库中使用的标识符必须与ASCII兼容,就像PEP 3131的policy section中所述的。
模块应使用简短的全小写名称。如果下划线能够提高可读性,那它可以用在模块命名中。尽管不鼓励使用下划线,但Python包也应使用短的全小写名称。
当用C或C++编写的扩展模块提供对应更高级别的的Python(例如,面向对象的接口)接口时,C / C++模块应具有一个下划线(例如_socket)。
类名通常应使用大驼峰命名约定。
如果接口在文档中有记录或主要用作回调的情况下,可以采用函数的命名约定。
请注意,内置(bulitin)名称有一个单独的约定:大多数内置名称是单个单词(或两个单词一起),而大驼峰约定仅用于exception名称和内置常量(builtin constants)。
在PEP 484中引入的type变量的名称通常应使用短名称的大驼峰命名法: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__机制以防止导出全局变量,或使用老早的约定在此类全局变量加下划线前缀(您可能需要这样做以表明这些全局变量是“模块非公开的” ”)。
函数名称应小写,必要时用下划线分隔单词,以提高可读性。
变量名与函数名遵循相同的约定。
仅在已经是主流风格(例如threading.py)的情况下才允许使用小驼峰命名法,以保持向后兼容性。
始终将self作为实例方法(instance methods)的第一个参数。
始终对类方法(class methods)的第一个参数使用cls。
如果函数参数的名称与保留关键字发生冲突,通常最好在末尾附加一个下划线,而不要使用缩写或拼写错误。 因此,class_优于clss。 (也许更好的办法是使用同义词来避免此类冲突。)
使用函数命名规则:小写,必要时用下划线分隔单词,以提高可读性。
仅对非公共方法和实例变量使用一个前导下划线。
为避免名称与子类发生冲突,请使用两个前导下划线来调用Python的改名机制。
Python用类名来修饰这些名称:如果Foo类具有名为__a的属性,则Foo .__ a无法访问它。 (坚持直接访问__a属性的用户仍然可以通过调用Foo._Foo__a获得访问权限。)通常,应仅使用双引号下划线来避免名称与设计为子类的类中的属性发生冲突。
注意:关于__name的使用存在一些争议(请参见下文)。
常量通常在模块级别定义,并以所有大写字母书写,并用下划线分隔单词。示例包括MAX_OVERFLOW和TOTAL。
始终确定类的方法和实例变量(统称为“属性”)应该是公共的还是非公共的。如有疑问,请选择非公开;后面将其公开比将公共属性设为不公开要容易。
公共属性指的是你期望与这个类不想关的用户使用并且承诺避免向后不兼容的更改。非公开属性是指不打算给第三方使用的属性;您不能保证非公共属性不会更改以及不会被删除。
我们在这里不使用术语“私有”,因为在Python中没有任何属性是真正私有的(通常没有不必要的工作量)。
另一类属性是属于“子类API”(在其他语言中通常称为“受保护”)的那些属性。某些类被设计为可继承的,以扩展或修改类行为的各个方面。在设计此类时,请务必明确决定哪些属性是公共属性,哪些是子类API的一部分,哪些属性仅由您的基类使用。
考虑到这一点,以下是Pythonic风格的指南:
任何向后兼容性保证都仅适用于公共接口。因此,重要的是用户能够清楚地区分公共接口和内部接口。
除非文档明确声明它们是临时接口或内部接口不受通常的向后兼容性保证,否则已说明文件的接口被视为公共接口。所有未记录的接口都应假定为内部接口。
为了更好地支持自我检查,模块应该使用__all__属性在其公共API中显式声明名称。将__all__设置为空列表表示该模块没有公共API。
即使正确设置了__all__,内部接口(包,模块,类,函数,属性或其他名称)仍应使用单个下划线作为前缀。
如果包含的命名空间(包,模块或类)是内部的,则该接口也被视为内部接口。
对于导入的名称实现时应仔细考虑。其他模块一定不要直接访问这些导入的名称,除非他们是这些模块API文档明确记录的,例如os.path或从子模块公开函数的包的__init__模块。
# Correct:
if foo is not None:
# Wrong:
if not foo is None:
# Correct:
def f(x): return 2*x
# Wrong:
f = lambda x: 2*x
第一种形式表示结果函数对象的名称专门为“ f”,而不是通用的’
从Exception而不是BaseException派生异常。从BaseException直接继承的异常通常是捕获它们本身就是错误行为的异常(Direct inheritance from BaseException is reserved for exceptions where catching them is almost always the wrong thing to do.)。
基于捕获异常的代码的区别来设计异常层次结构,而不是根据引发异常的位置。 旨在回答“出了什么问题?”,而不是以编程方式仅声明“发生了问题”(有关内置异常层次结构的学习示例,请参阅PEP 3151)
类命名约定在此处适用,但是如果异常是错误,则应在异常类中添加后缀“ Error”。用于非本地流控制或其他形式的信号的非错误异常不需要特殊的后缀。
适当使用异常链(exception chain)。在Python 3中,应使用“raise X from Y”来表示显式替换,而不会丢失原始回溯。
特意替换内部异常时(在Python 2中使用“raise X”或在Python 3.3+中使用“raise X from Y”),请确保将相关详细信息转移到新异常(例如,在将KeyError转换为AttributeError或将原始异常的文本嵌入新的异常消息中时保留属性名称)。
在Python 2中引发异常时,请使用raise ValueError(‘message’),而不是较旧的形式raise ValueError, ‘message’。
后一种形式不是合法的Python 3语法。
使用括号的形式还意味着,当异常参数很长或包含字符串格式时,由于包含括号,因此您无需使用行继续符。
捕获异常时,请尽可能提及特定的异常,而不要使用光秃秃的except: clause:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
一个光秃秃(bare)的except: clause 将捕获SystemExit和KeyboardInterrupt异常,这让使用Control-C中断程序更加困难,并且会掩盖其他问题。 如果要捕获所有表示程序错误的异常,请使用except Exception:(bare except等价于except BaseException: )。
一个好的经验法则是在这两种情况下限制使用bare ‘except’ 子句:
如果异常处理程序将打印输出或记录回溯;至少用户会意识到发生了错误。
如果代码需要做一些清理工作,但是解决这个问题的好办法是用raise. try … finally使异常向上传播。
在将捕获的异常绑定到名称时,最好使用Python 2.6中添加的显式名称绑定语法:
try:
process_data()
except Exception as exc:
raise DataProcessingFailedError(str(exc))
这是Python 3中唯一支持的语法,并且避免了与较早的基于逗号的语法相关的歧义问题。
# Correct:
try:
value = collection[key]
except KeyError:
return key_not_found(key)
else:
return handle_value(value)
# Wrong:
try:
# Too broad!
return handle_value(collection[key])
except KeyError:
# Will also catch KeyError raised by handle_value()
return key_not_found(key)
# Correct:
with conn.begin_transaction():
do_stuff_in_transaction(conn)
# Wrong:
with conn:
do_stuff_in_transaction(conn)
后面的示例没有提供任何信息来指示__enter__和__exit__方法除了在事务处理后关闭连接外,还在做其他事情。明确作用范围很重要。
# Correct:
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)
# Wrong:
def foo(x):
if x >= 0:
return math.sqrt(x)
def bar(x):
if x < 0:
return
return math.sqrt(x)
# Correct:
if foo.startswith('bar'):
# Wrong:
if foo[:3] == 'bar':
# Correct:
if isinstance(obj, int):
# Wrong:
if type(obj) is type(1):
在检查对象是否为字符串时,请记住它也可能是unicode字符串!在Python 2中,str和unicode具有一个公共基类basestring,因此您可以执行以下操作:
if isinstance(obj, basestring):
请注意,在Python 3中,unicode和basestring不再存在(只有str),bytes对象不再是一种字符串(取而代之的是整数序列)。
# Correct:
if not seq:
if seq:
# Wrong:
if len(seq):
if not len(seq):
# Correct:
if greeting:
# Wrong:
if greeting == True:
更糟糕的做法:
# Wrong:
if greeting is True:
# Wrong:
def foo():
try:
1 / 0
finally:
return 42
随着PEP 484的接受,函数注解的风格规则正在改变。
# type: ignore
放在文件顶部附近;这告诉类型检查器忽视所有注解。 (在PEP 484中可以找到更细粒度的方法来逃过类型检查程序的警告。)
PEP 526引入了变量注解。针对它们的风格建议与上述函数注解类似:
# Correct:
code: int
class Point:
coords: Tuple[int, int]
label: str = ''
# Wrong:
code:int # No space after colon
code : int # Space before colon
class Test:
result: int=0 # No spaces around equality sign
[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] Donald Knuth’s The TeXBook, pages 195 and 196.
[4] http://www.wikipedia.com/wiki/CamelCase
[5] Typeshed repo https://github.com/python/typeshed### 版权
[6] 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
[7] 悬挂缩进(Hanging indentation)是一种类型设置风格,其中段落中除第一行外的所有行均进行缩进。 在Python的上下文中,该术语用于描述一种风格,其中带括号的语句的左括号是该行的最后一个非空白字符,其后的行会缩进,直到右括号为止。
该文档已放置在公共领域。
来自:https://github.com/python/peps/blob/master/pep-0008.txt
在对这篇PEP 8文章翻译过程中,小编结合自己的经验修正了许多翻译软件翻译的语句,但还是有一些地方,是小编浅薄的经验所无法照顾的,就会加上原始英文,后续有新的理解会回来修正。希望大家喜欢这篇译文,对Guido大神推荐的pythonic风格学以致用!