长的导入模块语句注释里的URL不要使用反斜杠连接行

分号

不要将分号放在行尾,也不要使用分号将两个命令放在同一行。

行长

每行最多 80 个字符

例外:

长导入模块语句注释中的 URL

不要使用反斜杠连接行。

Python 将隐式连接括号、方括号和花括号之间的行。您可以利用此功能。如果需要,您可以在表达式周围添加一对额外的括号

Yes: foo_bar(self, width, height, color='black', design=None, x='foo',
 emphasis=None, highlight=0)
 if (width == 0 and height == 0 and
 color == 'red' and emphasis == 'strong'):

如果一个文本字符串不适合一行,可以使用括号来实现隐式连接:

x = ('This will build a very long long '
 'long long long long long long string')

在评论中,如有必要,将长 URL 放在一行中。

是:# 详情请参阅

#

否:# 详情请参阅

#

#v2.0/csv_file_name_extension_full_specification.html

注意上例中元素的缩进;您可以在本文的缩进部分找到解释。

括号

最好使用括号

不要在 return 或条件语句中使用括号,除非它们用于实现行连接。但是,元组周围的括号很好

Yes: if foo:
 bar()
 while x:
 x = bar()
 if x and y:
 bar()
 if not x:
 bar()
 return foo
 for (x, y) in dict.items(): ...
No: if (x):
 bar()
 if not(x):
 bar()
 return (foo)

缩进

4 个空格的缩进代码

永远不要使用制表符,也不要混合制表符和空格。对于线连接,您应该垂直对齐环绕元素(请参阅行长部分的示例),或者使用 4 空格悬挂缩进(在这种情况下,第一行不应有参数):

Yes: # 与左分隔符对齐

foo = long_function_name(var_one, var_two,

var_three, var_four)

# 与字典中的开始分隔符对齐

foo = {

long_dictionary_key: value1 +

值2,

}

# 4-空格悬挂缩进;第一行什么都没有

foo = long_function_name(

var_one、var_two、var_three、

var_four)

#字典中的4个空格悬挂缩进

foo = {

long_dictionary_key:

long_dictionary_value,

}

否:# 第一行禁止内容

foo = long_function_name(var_one, var_two,

var_three, var_four)

# 2-空格悬挂缩进禁止

foo = long_function_name(

var_one、var_two、var_three、

var_four)

# 字典中没有悬挂缩进

foo = {

long_dictionary_key:

long_dictionary_value,

}

空行

顶层定义之间留两行,方法定义之间留一行

在顶级定义(例如函数或类定义)之间留空两行。方法定义、类定义和第一个方法之间应该有一个空行。在函数或方法中,如果您觉得合适,请留空一行。

空格

根据标准印刷约定在标点符号周围使用空格

括号之间没有空格。

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

不要在逗号、分号、冒号之前放置空格,而是在它们之后(行尾除外)。

Yes: if x == 4:
 print x, y
 x, y = y, x
No: if x == 4 :
 print x , y
 x , y = y , x

参数列表、索引或切片的左括号前不应有空格。

Yes: spam(1)
no: spam (1)
Yes: dict['key'] = list[index]
No: dict ['key'] = list [index]

在二元运算符的两边放一个空格,如赋值(=)、比较(==、、!=、、=、in、not in、is、is not)、布尔值(and、or、not )。至于算术运算符两边的空格怎么用,需要自己判断。但双方必须一致。

Yes: x == 1
No: x<1

当“=”用于表示关键字参数或默认参数值时,不要在其周围使用空格。

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:
 foo = 1000 # comment
 long_name = 2 # comment that should not be aligned
 dictionary = {
 "foo": 1,
 "long_name": 2,
 }
No:
 foo = 1000 # comment
 long_name = 2 # comment that should not be aligned
 dictionary = {
 "foo" : 1,
 "long_name": 2,
 }

社邦

大多数 .py 文件不必以 #! 开头。根据 PEP-394计算器中的感叹号是什么意思,程序的主文件应该以 #!/usr/bin/python2 或 #!/usr/bin/python3 开头。

(译者注:在计算机科学中,Shebang(也称为 Hashbang)是由井号和感叹号 (#!) 组成的一行字符串,它作为 a 的第一行的前两个字符出现文本文件,当文件中有Shebang时,类Unix操作系统的程序加载器会分析Shebang后的内容,将这些内容作为解释器指令,调用指令,使用包含Shebang的文件路径作为解释器参数。例如,以指令#!/bin/sh 开头的文件在执行时实际上会调用/bin/sh 程序。)

最初用于帮助内核找到 Python 解释器计算器中的感叹号是什么意思,但在导入模块时会被忽略。因此,只需要包含在直接执行的文件中

评论

确保对模块、函数、方法和内联注释使用正确的样式

文档字符串

Python 有一种独特的注释方式:使用文档字符串。文档字符串是包、模块、类或函数中的第一条语句。这些字符串可以通过对象的 __doc__ 成员自动提取,并由 pydoc 使用。 (您可以尝试在您的模块上运行 pydoc 并查看它的外观)。我们对文档字符串的约定是使用三个双引号 """ (PEP-257)。文档字符串应按如下方式组织:首先是一个以句点、问号或感叹号结尾的单行摘要(或者文档字符串是只有一行)。然后是一个空行。然后是文档字符串的其余部分,应该与文档字符串相同 对齐字符串第一行的第一个引号。下面是文档字符串的更多格式规范。

模块

每个文件都应包含一个许可证模板。根据项目使用的许可证(例如,Apache 2.0、BSD、LGPL、GPL),选择适当的模板。

函数和方法

下面提到的函数包括函数、方法和生成器。一个函数必须有一个文档字符串,除非它满足以下条件:文档字符串应该包含函数做什么的详细描述,以及它的输入和输出。一般来说,不应该描述“怎么做”,除非是一些复杂的算法。文档字符串应该提供足够的信息,当有人编写代码来调用函数时,他不需要看一行代码,只看文档字符串。 对于复杂的代码,在代码旁边添加注释比使用文档字符串更有意义。功能的几个方面应记录在特定部分,如下所述。每个部分都应以标题行开头。标题行以冒号结尾。除标题行外,其余部分应缩进 2 个空格。

def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
 """Fetches rows from a Bigtable.
 Retrieves rows pertaining to the given keys from the Table instance
 represented by big_table. Silly things may happen if
 other_silly_variable is not None.
 Args:
 big_table: An open Bigtable Table instance.
 keys: A sequence of strings representing the key of each table row
 to fetch.
 other_silly_variable: Another optional variable, that has a much
 longer name than the other args, and which does nothing.
 Returns:
 A dict mapping keys to the corresponding table row data
 fetched. Each row is represented as a tuple of strings. For
 example:
 {'Serak': ('Rigel VII', 'Preparer'),
 'Zim': ('Irk', 'Invader'),
 'Lrrr': ('Omicron Persei 8', 'Emperor')}
 If a key from the keys argument is missing from the dictionary,
 then that row was not found in the table.
 Raises:
 IOError: An error occurred accessing the bigtable.Table object.
 """
 pass

一个类的定义下应该有一个描述类的文档字符串。如果您的类具有公共属性(Attributes),那么文档中应该有一个 Attributes 部分。并且应该遵守和函数参数相同的格式

class SampleClass(object):
 """Summary of class here.
 Longer class information....
 Longer class information....
 Attributes:
 likes_spam: A boolean indicating if we like SPAM or not.
 eggs: An integer count of the eggs we have laid.
 """
 def __init__(self, likes_spam=False):
 """Inits SampleClass with blah."""
 self.likes_spam = likes_spam
 self.eggs = 0
 def public_method(self):
 """Performs operation blah."""

块和行注释

注释是代码中最重要的部分。如果你必须在下一次代码审查中解释它,你现在应该评论它。对于复杂的操作,应该在操作开始之前。写几行评论。对于一目了然的代码,在行尾添加注释。

# We use a weighted dictionary search to find out where i is in
# the array. We extrapolate position based on the largest num
# in the array and the array size and then do binary search to
# get the exact number.
if i & (i-1) == 0: # True if i is 0 or a power of 2.

为提高可读性,注释与代码之间的距离应至少为 2 个空格。另一方面,永远不要描述代码。假设阅读代码的人比你更懂 Python,他只是不知道你的代码做了什么。

# BAD COMMENT: 现在遍历 b 数组并确保每当 i 出现时

#下一个元素是i+1

如果一个类没有从另一个类继承,它显式地从对象继承。嵌套类也是如此。

Yes: class SampleClass(object):
 pass
 class OuterClass(object):
 class InnerClass(object):
 pass
 class ChildClass(ParentClass):
 """Explicitly inherits from another class already."""
No: class SampleClass:
 pass
 class OuterClass:
 class InnerClass:
 pass

从对象继承是为了使属性正常工作,这可以保护您的代码免受 PEP-3000 的特定潜在不兼容性的影响。这也定义了一些特殊的方法,这些方法实现了对象的默认语义,包括__new__、__init__、__delattr__、__getattribute__、__setattr__、__hash__、__repr__和__str__。

字符串

即使参数都是字符串,也可以使用 % 运算符或格式化方法来格式化字符串。但是不能一概而论,需要在+和%之间进行判断。

Yes: x = a + b
 x = '%s, %s!' % (imperative, expletive)
 x = '{}, {}!'.format(imperative, expletive)
 x = 'name: %s; score: %d' % (name, n)
 x = 'name: {}; score: {}'.format(name, n)
No: x = '%s%s' % (a, b) # use + in this case
 x = '{}{}'.format(a, b) # use + in this case
 x = imperative + ', ' + expletive + '!'
 x = 'name: ' + name + '; score: ' + str(n)

避免在循环中使用 + 和 += 运算符来累积字符串。由于字符串是不可变的,因此这样做会创建不必要的临时对象并导致二次而非线性运行时。或者,您可以将每个子字符串添加到列表中,然后在循环后使用 .join 加入列表。 (或者将每个子字符串写入 cStringIO.StringIO 缓冲区。)

Yes: items = ['']
 for last_name, first_name in employee_list:
 items.append('' % (last_name, first_name))
 items.append('
%s, %s
') employee_table = ''.join(items) No: employee_table = '' for last_name, first_name in employee_list: employee_table += '' % (last_name, first_name) employee_table += '
%s, %s
'

在同一文件中一致地使用字符串引号。使用单引号 ' 或双引号 " 来引用字符串并在同一个文件中使用它。您可以在字符串中使用另一个引号来避免在字符串中使用。GPyLint 已添加此检查。

(译者注:GPyLint怀疑是笔误,应该是PyLint。)

Yes:
 Python('Why are you hiding your eyes?')
 Gollum("I'm scared of lint errors.")
 Narrator('"Good!" thought a happy Python reviewer.')
No:
 Python("Why are you hiding your eyes?")
 Gollum('The lint. It burns. It burns us.')
 Gollum("Always the great lint. Watching. Watching.")

对多行字符串使用三重双引号 ''' 而不是三重单引号 '''。使用三元组 ''' 为非文档字符串的多行字符串来标识引用。文档字符串必须使用三个双引号 """。但是请注意,使用隐式行连接通常更清楚,因为多行字符串的缩进方式与程序的其余部分不一致。

Yes:
 print ("This is much nicer.
"
 "Do it this way.
")
No:
 print """This is pretty ugly.
 Don't do this.
 """

文件和套接字


在文件和套接字的末尾显式关闭它。

除了文件之外,套接字或其他类似文件的对象也被不必要地打开了,有很多副作用,例如:

它们可能会消耗有限的系统资源,例如文件描述符。如果这些资源在使用后没有及时返回系统,用于处理这些对象的代码就会消耗资源。持有文件将阻止其他操作,例如移动和删除文件。只是在逻辑上关闭文件和套接字,那么它们仍然可能被它们的共享程序无意中读取或写入。只有当它们真正关闭时,对于任何读取或写入的尝试都会抛出异常并使问题迅速显现。

再者,想象当文件对象被破坏时,文件和sockets会自动关闭,想把文件对象的生命周期和文件的状态捆绑在一起是不现实的。由于以下原因:

没有办法确保运行时环境会真正执行文件的解构。不同的 Python 实现使用不同的内存管理技术,例如延迟垃圾处理机制。延迟的垃圾处理机制可能会导致任意确定对象的生命周期。无限扩展。对文件的意外引用可能导致文件的保存时间比预期的要长(例如异常跟踪,包括全局变量等)。

建议使用“with”语句来管理文件:

with open("hello.txt") as hello_file:
 for line in hello_file:
 print line

对于不支持使用“with”语句的类文件对象,使用 contextlib.closure():

import contextlib
with contextlib.closing(urllib.urlopen("http://www.python.org/")) as front_page:
 for line in front_page:
 print line

如果 Legacy AppEngine 中 Python 2.5 的代码使用“with”语句,则需要添加“from __future__ import with_statement”。

待办事项说明

对临时代码使用 TODO 注释,这是一种短期解决方案。不完美,但足够好。

TODO 注释的开头应包含字符串“TODO”,后跟您的姓名、电子邮件地址或括号中的其他标识符。然后是一个可选的冒号。后面必须跟一行注释,说明要做什么。主要目的是有一个统一的 TODO 格式,以便添加评论的人可以搜索它(并按需提供更多详细信息)。写 TODO 评论并不能保证写的人会自己解决问题。当你写一个 TODO 时,请写上你的名字。

# TODO(kl@gmail.com): Use a "*" here for string repetition.
# TODO(Zeke) Change this to use relations.

如果您的 TODO 是“将来做某事”的形式,那么请确保包含特定日期(“2009 年 11 月解决”)或特定事件(“等到所有客户都可以处理”)XML请求删除此代码”)。

导入格式

每个导入都应该在自己的行中

是的:导入操作系统

导入系统

否:导入操作系统、系统

导入应该始终放在文件的顶部,模块注释和文档字符串之后,模块全局变量和常量之前。导入应该从最常见到最不常见进行分组:

标准库导入第三方库导入应用特定导入

在每个分组中,应根据每个模块的完整包路径按字典顺序排序,忽略大小写。

import foo
from foo import bar
from foo.bar import baz
from foo.bar import Quux
from Foob import ar

声明

通常每个语句都应该在自己的行中

但是,如果测试结果和测试语句位于同一行,您也可以将它们放在同一行。在 if 语句的情况下,只有在没有 else 时才这样做。特别是,永远不要使用 try/except 这样做是因为 try 和 except 不能在同一行。

Yes:
 if foo: bar(foo)
No:
 if foo: bar(foo)
 else: baz(foo)
 try: bar(foo)
 except ValueError: baz(foo)
 try:
 bar(foo)
 except ValueError: baz(foo)

访问控制

在 Python 中,对于琐碎和不太重要的访问函数,您应该直接使用公共变量而不是它们,这样可以避免额外的函数调用开销。添加更多功能时,可以使用属性(property)来保持语法一致性。

(译者注:看重封装的面向对象的程序员可能会反感,因为他们被教导所有成员变量必须是私有的!实际上,这确实有点麻烦。尝试 Go 并拥抱Pythonic哲学)

另一方面,如果访问更复杂,或者变量访问开销很大,那么您应该使用 get_foo() 和 set_foo() 之类的函数调用。如果之前的代码行为允许通过属性访问,则不要将新的访问器绑定到属性。这样,任何试图以旧方式访问变量的代码都将无法工作,并且用户将意识到复杂性的变化。

命名

module_name、package_name、ClassName、method_name、ExceptionName、function_name、GLOBAL_VAR_NAME、instance_var_name、function_parameter_name、local_var_name。

应该避免的名字

命名约定

Python之父Guido推荐的规范

TypePublicInternalModuleslower_with_under_lower_with_underPackageslower_with_under

ClassesCapWords_CapWordsExceptionsCapWords

Functionslower_with_under()_lower_with_under()全局/类常量CAPS_WITH_UNDER_CAPS_WITH_UNDERGlobal/类变量slower_with_under_lower_with_underInstance Variableslower_with_under_lower_with_under (protected) or __lower_with_under (private)Method Nameslower_with_under()_lower_with_under() (protected) or __lower_under

局部变量slower_with_under

主要

即使是打算用作脚本的文件也应该是可导入的。并且一个简单的导入不应该导致脚本的主要功能被执行,这是一个副作用。 main 函数应该放在 main() 函数中。

在 Python 中,pydoc 和单元测试要求模块是可导入的。您的代码应始终在执行主程序之前检查是否 __name__ == '__main__',以便在导入模块时不会执行主程序。

def main():
 ...
if __name__ == '__main__':
 main()

导入模块时会执行所有顶级代码。注意不要调用函数、创建对象或执行使用 pydoc 时不应该执行的操作。

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论