分号
不要将分号放在行尾,也不要使用分号将两个命令放在同一行。
行长
每行最多 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 = ['
%s, %s |
%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 时不应该执行的操作。
请登录后发表评论
注册
社交帐号登录