1、引言
本文档给出了 Python 编码规约,主要 Python 发行版中的标准库即遵守该规约。对于 C 代码风格的 Python 程序,请参阅配套的 C 代码风格指南。
本文档和 PEP 257(文档字符串规约)是根据 Guido 的 Python 风格指南一文改编的,其中还增加了 Barry 提出的一些风格指南。
风格指南并非一成不变,它本身也在不断发展,过去的惯例会因语言本身的变化而过时。
许多项目有自己的编码风格,在发生冲突时,这类项目的风格指南应优先考虑。
2、固执己见必成心灵之魔
Guido 认为:代码被阅读之频繁远甚于其被编写。所以,这里提供的准则旨在提高代码的可读性并使其在各种 Python 代码中保持一致。如 PEP 20 所述,“可读性至关重要”。
风格指南是有关一致性的重要规约。书写与此风格指南一致的代码很重要,书写与项目风格一致的代码更加重要,在一个模块或函数内, 书写风格一致的代码超级重要。
所以,风格指南并不适用于所有情况,要知道什么时候不一致,这需要你运用自己的智慧进行判断。多看一些例子,选择你认为最好的那个,必要的时候要懂得向别人请教。
尤其注意:不要为了满足风格指南而破坏与过去代码风格的兼容性!
以下情况可以不必考虑风格指南:
- 即使对于习惯此风格代码的人,应用此风格指南也会使代码的可读性降低。
- 为了与上下文代码风格一致(可能由于历史原因,上下文的风格也违背了本指南),
当然这也是一个规范代码风格的机会(通过改变上下文的风格)。 - 有些代码早于此风格指南出现并且没有其他理由要修改这些代码。
- 代码需要与旧版本的 Python 代码兼容,但旧版本不支持此风格指南。
3、代码布局
每级缩进对应四个空格。
()、[]或者{}可以隐式的换行,三种括号所包裹的代码要么垂直对齐,要么悬挂缩进。当使用悬挂缩进时,应该注意:参数不能放在首行,续行要再缩进一级以便和后边的代码区别开。
当 if 语句的条件部分很长以至于需要将其写成多行时,需要注意,if 和单个空格以及左括号正好是 4 个空格缩进,这可能与嵌套在if语句中的代码块产生冲突。本文档不提供确切的方法来解决条件行和 if 语句的嵌套代码块的冲突。
推荐使用空格控制缩进。
长期以来,一直推荐的风格是在二元运算符之后换行,但是这会影响代码可读性,一是会使运算符分散在屏幕的不同列上,二是会使每个运算符留在前一行,并远离操作数分离。必须人为地判断应该加上或者减去哪些东西,这就增加了人眼的负担。
为了解决这一可读性问题,数学家和出版商遵循了相反的规约。Donald Knuth 在他的《Computers and Typesetting》丛书中解释了这一规约。“虽然段落中的公式总是在二元运算符后换行,但显示公式时总是在二元运算符之前换行。”
遵循数学上的传统可以写出可读性更好的代码。
顶级函数和类的定义前后空两行。
类内部的方法定义前后空一行。
可以使用额外的空行(尽量少)来分隔相关函数组。一系列相关的仅占一行的函数之间的空白行可以省略(比如一系列虚函数)。
在函数内部可以使用空行(尽量少)来分割逻辑上的代码块。
当前核心的 Python 发行版本一直使用 utf-8 编码,在 Python2 中则使用 ASCII 编码。
Python2 使用 ASCII ,Python3 使用 utf-8 编码,这在文件中不需要进行编码声明。
导入语句应该分开写,而不是都放到一行。
导入语句一般放在文件开头,在模块注释和文档字符串之后,模块全局变量和常量之前。
注意分组导入,并遵循一下顺序:
- 标准库导入
- 相关的第三方包导入
- 本地应用或库的特定导入
4、字符串引用
在 Python 中,单引号字符串和双引号字符串是一样的。本 PEP 文档在这一点上不做要求,选用一种并坚持下去就好。当字符串本身包含单引号或者双引号时,那就选用未包含的引号来表示字符串,这样可以避免使用\
,代码也更易读。
如果使用三引号形式的字符串,则用双引号"
组成三引号"""
,这样可以和 PEP 257 中的文档字符串规约保持一致。
5、表达式和语句中的空格
避免使用过多空格。
-
避免任何行末空格,因为通常不可见,它们容易让人困惑。例如,
\
后跟一个空格和一个新行,\
将不会被当作续行符。有些编辑器可以自动去除行末空格。对于这种情况,许多项目(如CPython本身)会用钩子做提交前检查。 -
这些二元运算符两边通常保留一个空格:赋值运算符(=),增强的复制运算符(+=,-=等)关系运算符(==,<,>,!=,<=,>=,in,not in,is,is not),布尔运算符(and,or,not)。
6、何时在末尾加逗号
末尾的逗号通常是可选的。但是,在定义单元素元组时是必须的(而且在 Python2 中,逗号对 print 语句有特殊语义)。清楚起见,建议使用括号括起来(在技术上是冗余的)。
7、注释
和代码相矛盾的注释还不如没有注释。当代码更新时,要优先更改注释,使其保持最新状态。
注释应该是完整的句子。第一个单词首字母要大写,除非是一个小写字母开头的标识符(永远不要修改标识符的大小写!)。
块注释通常由完整句子构成的一个或多个段落组成,每个句子都以句号结束。
在多语句注释中,除了最后一条句子,应当在句尾的句号后面加两个空格。
如果使用英文写作,参考 Strunk 和 White 的著作。
来自非英语国家的 Python 程序员们:请书写英文注释,除非你 120% 确定你所写的代码永远不会被不懂你所用语言的人读到。
(1)块注释
块注释一般写在对应代码之前,并且和对应代码有同样的缩进级别。块注释以一个 # 和一个空格打头(除非注释内的文本也有缩进)。
块注释中的段落用以单个 # 字符开头的空行分隔。
(2)行内注释
少用行内注释。
行内注释和代码语句写在同一行,至少以两个空格分隔。并且也以一个 # 和一个空格打头。
要写出好的文档字符串(又名“docstrings”),请参阅 PEP 257 。
8、命名规约
Python 库的命名规约有些混乱,所以我们无法就此保持完全一致。但我们当前还是有一些值得推荐的命名规约。书写新的模块和包(包括第三方框架)时,应当遵循这些标准。但是如果现有的库遵循了不同的代码风格,那么应该保持内部代码的一致性。
(1)首要原则
对用户可见的公共部分 API ,其名称应该反应出其用途而不是实现。
(2)描述:命名风格
不同的命名风格有很多,最好能从应用他们的代码而识别出对应命名风格。
- _single_leading_underscore:内部使用的弱标识。例如,
from M import *
语句并不会导入以下划线开头的对象。 - single_trailing_underscore_:以单下划线结尾避免和 Python 关键字冲突。例如:
类命名应使用驼峰命名法。
函数名应该小写,必要时可使用下划线分隔单词来提高可读性。
变量名和函数名遵循相同的规约。
实例方法的第一参数永远都是self
。
类方法的第一个参数永远都是cls
。
当函数的参数名称与保留关键字冲突时,相比使用缩写或拼写简化,使用以下划线结尾的名称更好。所以class_
比clss
更好。(或许更好的方法是通过使用同义词来避免这种冲突。)
使用函数命名规约:单词小写,必要时以下划线分隔。
非公共方法和实例变量以下划线打头。
为避免和子类产生命名冲突,使用双下划线打头的方式来调用 Python 的命名修饰机制。
常量通常是在模块级别定义的,并且全部采用大写字母,单词之间以下划线分隔。
永远记得区别类方法和实例变量(属性)应该是公开的还是非公开的。如果有所疑虑,就选择非公开。因为,将非公开属性变成公开属性和容易,反之很难。
类中的公开属性是留给与此类无关的客户使用的,并且保证向后的兼容性。非公开属性是那些不打算让第三方使用的部分,这类属性可能被更改甚至移除。
这里,我们不使用“私有的”这一术语,因为在 Python 中没有真正的私有属性(避免了大量不必要的工作)。
另一类属性是子类 API (在其他语言中经常被称为“受保护的”)的一部分。有些类是为继承而设计的,要么会扩展要么会修改类的行为。当设计这样的类时,注意,一定要明确的说明哪些属性是公开的,哪些是子类 API,哪些是真正只被基类调用的。
考虑到这些,得出以下 Python 风格指南:
-
公开属性不应该以下划线打头。
-
如果你的公开属性名与保留关键字冲突,那就在属性名后增加一条下划线。这比采用缩略词或简写方式更好。(然而,虽说有了这条规则,对于任何类变量或参数,尤其是类方法的第一个参数,
cls
都是更好的选择,因为这是通识。)注意 1:对于类方法,参考之前的参数命名建议。
-
对于简单的公共数据属性,最好只公开属性名,不要有访问器和修改器。请记住,如果您需要对简单的数据属性增加功能行为,Python 为功能增强提供了一条简单的途径。这种情况下使用
properties
注解把功能实现隐藏在简单数据属性访问语法之后。注意 1:
properties
注解仅对新式类起作用。注意 2:尽量消除功能行为的副作用,尽管缓存之类的副作用没有什么坏处。
注意 3:避免对计算量大的操作使用
properties
注解,属性注解会让调用者认为开销相对较低。 -
如果你的类会被子类继承,但有些属性你又不想让子类使用,可以考虑用双下划线打头结尾没有下划线的方式命名。这样会调用 Python 的命名修饰算法,将类名修饰添加到属性名中。这样可以避免属性命名冲突,因为子类可能在不经意间设置同名的属性。
注意 1:命名修饰仅仅是简单的用类名修饰了属性名,如果你在子类中同时使用类名+属性名,也会遇到命名冲突问题。
注意 2:命名修饰可以有特定的用途,比如调试和
__getattr__()
,只是不够方便。然而,命名修饰算法已经有很好的文档化了,手动执行也很容易。注意 3:不是所有人都喜欢命名修饰,要尽力在避免命名冲突和方便调用之间寻求一种平衡。
9、编程建议
代码应该以不影响其他Python实现(PyPy,Jython,IronPython,Cython,Psyco等)的方式编写。
与 None 这样的单例做比较应该使用is
或者is not
,而不是等号(==)。
建议使用is not
运算符,而不是not ... is
。虽然两个表达式功能相同,但前者可读性更高,应该被选用。
用富比较实现排序操作的时候,最好实现全部六个比较运算符(__eq__
,__ne__
,__lt__
,__le__
,__gt__
,__ge__
),而不是依靠其他代码来进行特定比较。
为最大限度的降低工作量,functools.total_ordering()
装饰器提供了一个工具来生成缺少的比较方法。
PEP 207 指出 Python 实现了反射机制。因此,解释器可能使用y > x
替换x < y
,使用y >= x
替换x <= y
,也可能交换x == y
和x != y
的操作数。sort()
和min()
操作使用了<
运算符,max()
函数使用了>
运算符。但是,最好是六个操作符都实现,以免在其他情况下出现混淆。
要使用定义语句,而不是利用赋值语句为某个标识符绑定lambda
表达式。
应从 Exception 中而不是 BaseException 中继承异常,捕获直接继承自 BaseException 的异常通常都是错误的。
适当的使用异常链。在 Python3 中,应该使用“raise X from Y”来指示显示替换,这样不会丢失原始的回溯。
捕获异常时,尽可能使用明确的异常,而不是使用一个空的except:
子句。
在捕获操作系统错误时,首选 Python3.3 中引入的显式异常层次结构,而不是检查error
值。
另外,对于所有的 try/except 子句,应将 try 子句限制为必要的最小的代码量。再者,可以避免掩盖问题。
当某个资源仅被本地的特定代码段使用时,请使用 with 语句以确保资源使用后可以被及时可靠地清理。也可以使用 try/finally 语句。
坚持使用 return 语句。函数中的所有 return 语句都应该返回一个表达式或者 None。如果有 return 语句返回了一个表达式,那么,没有返回值的语句都要明确地用return None
说明。如果可能的话,应该以一条清晰的 return 语句作为函数的结尾。
使用''.startswith()
和''.endswith()
而不是字符串切片操作来检查前缀和后缀。
对象类型比较应该用 isinstance() 而不是直接比较。
对于序列(字符串、列表、元组)来说,空序列的布尔值为 False。
标签:语句,Python,python,代码,运算符,PEP8,使用,属性 From: https://www.cnblogs.com/tangjicheng/p/17134125.html