Python代码规范PEP8总结

原文

https://legacy.python.org/dev/peps/pep-0008/

中文翻译版本

https://blog.csdn.net/ratsniper/article/details/78954852

PEP8代码规范主要分为四个部分

  1. 代码布局
  2. 空格的使用
  3. 注释规范
  4. 命名规范

1.代码布局

1.1 Indentation 缩进

每一级缩进建议使用4个空格长度,并保持所有缩进都使用该标准,四空格的要求缩进对于挂行缩进是可选的

缩进方式的选择

缩进方式首选空格

当然,也可以使用制表符(Tab),但是制表符只能和同样使用制表符缩进的代码保持一致。

也就是说:
缩进不可以空格和制表符混用
缩进不可以空格和制表符混用
缩进不可以空格和制表符混用

换行与缩进规范

——续行缩进应与包裹元素对齐

  1. 圆括号、方括号、花括号内的隐式行连接垂直对齐
 与左括号对齐
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

注意:没有使用垂直对齐的时候,禁止把参数放在第一行!

  1. 挂行对齐(第一行不应该有参数)
 挂行缩进应该再换一行
foo = long_function_name(
    var_one, var_two,
    var_three, var_four)
    #其他行
    print(var_one)

注意:挂行缩进部分缩进长度,应与其他行进行区分

——条件语句缩进

语句的条件部分长到需要换行写的时候,注意可以在两个字符关键字的连接处(比如if),增加一个空格,再增加一个左括号来创造一个4空格缩进的多行条件。
区分 if 的条件代码和内嵌代码。可使用的选项包括但不限于下面几种情况:

1.  没有额外的缩进

if (this_is_one_thing and
    that_is_another_thing):
    do_something()

2.  增加一个注释,通过注释分区条件代码和内嵌代码

if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

3.  在条件判断的语句添加额外的缩进

if (this_is_one_thing
        and that_is_another_thing):
    do_something()

——括号结构的缩进

  1. 多行结构中的大括号/中括号/小括号,的右括号可以与内容对齐单独起一行作为最后一行的第一个字符
my_list = [
    1, 2, 3,
    4, 5, 6,
    ]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )
  1. 也可以与多行结构的第一行第一个字符对齐
my_list = [
    1, 2, 3,
    4, 5, 6,
]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

——每行多长必须换行缩进?

所有行限制的最大字符数为79。
没有结构化限制的大块文本(文档字符或者注释),每行的最大字符数限制在72。

——较长的代码行怎样换行缩进

  1. 括号
    在小括号,中括号以及大括号中的隐式续行方式。通过小括号内表达式的换行方式将长串折成多行。这种方式应该优先使用,而不是使用反斜杠续行。
  2. 反斜杠
    反斜杠有时依然很有用。比如,比较长的,多个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())

——二元运算符的换行与缩进

在二元运算符之前开始换行并缩进

不推荐: 操作符离操作数太远
income = (gross_wages +
          taxable_interest +
          (dividends - qualified_dividends) -
          ira_deduction -
          student_loan_interest)

推荐:运算符和操作数很容易进行匹配
income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

1.2 Blank Lines空行

  • 顶层函数和类的定义,前后用两个空行隔开。
  • 类里的方法定义之间用一个空行隔开。

谨慎使用以下规则:

  • 相关的功能组可以用额外的空行隔开

  • 一堆相关的单行代码之间的空白行可以省略

  • 在函数中使用空行来区分逻辑段

  • Python接受control-L(即^L)换页符作为空格;许多工具把这些字符当作页面分隔符,所以你可以在文件中使用它们来分隔相关段落。请注意,一些编辑器和基于Web的代码阅读器可能无法识别control-L为换页,将在其位置显示另一个字形。

1.3 Source File Encoding文件编码

Python核心发布版本中的代码总是以UTF-8格式编码(或者在Python2中用ASCII编码)。

使用ASCII(在Python2中)或UTF-8(在Python3中)编码的文件不应具有编码声明。

Python标准库中的所有标识符必须使用ASCII标识符,并在可行的情况下使用英语单词(在许多情况下,缩写和技术术语是非英语的)。

此外,字符串文字和注释也必须是ASCII。
如果包含非ASCII字符,使用\x,\u,\U , 或者 \N 进行转义来包含非ASCII字符。

1.4 Imports 导入

——导入的格式

  • 导入的内容位置不明确
推荐: import os
     import sys

不推荐:  import sys, os
  • 导入的内容在位置明确
from subprocess import Popen, PIPE

——导入顺序

  • 导入总是位于文件的顶部,在模块注释和文档字符串之后,在模块的全局变量与常量之前。

导入应该按照以下顺序分组:

  1. 标准库导入
  2. 相关第三方库导入
  3. 本地应用/库特定导入

你应该在每一组导入之间加入空行。

——导入路径

导入路径分为三种:1.纯绝对路径 2.显式地指定相对路径3.隐式相对路径

推荐使用绝对路径导入
使用绝对路径会明确引入内容的真实路径,更加可读并且性能更好(至少能提供更好的错误信息):

import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example

当绝对路径的引入层级多,结构复杂时,显式地指定相对引入路径是允许的

from . import sibling
from .sibling import example

不建议使用隐式相对路径引入,例如以下:

import xxx from ../../../include/img/icon/xxx

——导入包中的类

当从一个包含类的模块中导入类的时候,常这样进行:

from myclass import MyClass
from foo.bar.yourclass import YourClass

如果大小写会出现冲突,可以这样写:

import myclass
import foo.bar.yourclass

在使用的时候自行加上类的使用:

myclass.MyClass

foo.bar.yourclass.YourClass

——导入时对通配符*的使用

应该避免对通配符的使用*

因为不明确引入的内容是否会和当前文档中的内容名称产生冲突,会使得读取接口和许多自动化工具之间产生混淆。

对于通配符的导入,有一个防御性的做法,即将内部接口重新发布为公共API的一部分(例如,用可选加速器模块的定义覆盖纯Python实现的接口,以及重写那些事先不知道的定义)。
当以这种方式重新发布名称时,以下关于公共和内部接口的准则仍然适用。

1.5 Module level dunder names 模块级的“呆”名

all , __author__ , __version__ 等这样的模块级“呆名“(也就是名字里有两个前缀下划线和两个后缀下划线)

应该放在文档字符串的后面,以及除from __future__ 之外的import表达式前面

"""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

1.6字符串的引号使用

  • 单引号与双引号的选择和使用

在Python中,单引号和双引号字符串效果是相同的,可以主要使用任意一种不做要求

当一个字符串中包含单引号或双引号的字符时,在外层包裹不同的符号,来避免使用反斜杠,从而提高可读性。

  • 三引号

三引号字符串为了进行与```符号的区分,选择双引号字符"""进行使用

1.7复合语句

复合语句通常是不允许的,这样会降低可读性,请将代码拆分为多行设置

2.空格的使用

——括号附近的空格

  • 不要在小括号、中括号、大括号之后或之前添加空格
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:
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]

NO:
ham[lower + offset:upper + offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : upper]
ham[ : upper]

——二元运算符

  • 记得总是在二元运算符两边添加一个空格:赋值(=),增量赋值(+=,-=),比较(==,<,>,!=,<>,<=,>=,in,not,in,is,is not),布尔(and, or, not)。
  • 如果语句中有不同优先级的运算符,请在最低级运算符符周围添加一个空格(例如有乘除加减,加减就是最低级运算符)
  • 如果语句中有不同优先级的运算符,优先运算的运算符不用添加空格
YES:
i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)

NO:
i=i+1
submitted +=1
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a + b) * (a - b)

——赋值

  • 在制定关键字参数或者默认参数值的时候,不要在=附近加上空格。
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:
def munge(sep: AnyStr = None): ...
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...

NO:
def munge(input: AnyStr=None): ...
def munge(input: AnyStr, limit = 1000): ...

——对齐

  • 不要使用添加多余的空格来试图结构对齐
YES:
x = 1
y = 2
long_variable = 3

NO:
x             = 1
y             = 2
long_variable = 3

——语句尾部

  • 避免在尾部添加空格。因为尾部的空格通常都看不见,会产生混乱。比如,一个反斜杠后面跟一个空格的换行符,不算续行标记。

3.Comments 注释

  • 注释应该是完成的句子,给阅读者最低的理解成本
  • 注释结束的时候应添加两个空格

3.1Block Comments 块注释

  • 块注释通常适用于跟随它们的某些(或全部)代码,并缩进到与代码相同的级别。
  • 块注释的每一行开头使用一个#和一个空格(除非块注释内部缩进文本)。
  • 块注释内部的段落通过只有一个#的空行分隔。
# line01
# line02
#
# line03

3.2Inline Comments 行内注释

  • 行内注释是与代码语句同行的注释。
  • 行内注释和代码至少要有两个空格分隔。注释由#和一个空格开始。
x = x + 1                 # Compensate for border

3.3Documentation Strings 文档字符串

  • 要为所有的公共模块,函数,类以及方法编写文档说明。非公共的方法没有必要,但是应该有一个描述方法具体作用的注释。这个注释应该在def那一行之后。
  • 特别需要注意的是,多行文档说明使用的结尾三引号应该自成一行
"""Return a foobang

Optional plotz says to frobnicate the bizbaz first.
"""
  • 对于单行的文档说明,尾部的三引号应该和文档在同一行。
"""Return a foot """

4.Naming Conventions 命名规范

4.1命名原则

那些暴露给用户的API接口的命名,应该遵循反映使用场景而不是实现的原则。

4.2命名风格

以下是常见的命名方式

  • b(单个小写字母)
  • B(单个大写字母)
  • show(统一小写字母)
  • show_title(使用下划线分隔小写字母)
  • SHOW(统一大写字母)
  • SHOW_TITLE(使用下划线分隔大写字母)
  • ShowTitle(大驼峰命名法)
  • showTitle(小驼峰命名法)
  • Show_Title(各种混用)

另外,下面这种用前缀或结尾下划线的特殊格式是被认可的(通常和一些约定相结合):

  • _show(单下划线开头)。受保护的对象成员,在类/对象外部不可访问
  • show_(单下划线结尾)。这是避免和Python内部关键词冲突的一种约定(例:class_=’ClassName’)
  • __show(双下划綫开头)。当这样命名一个类的属性时,调用它的时候名字会做矫正:(在类FooBar中,__boo变成了_FooBar__boo)
  • __show__(双下划綫开始,双下划綫结尾)。私有的对象成员,在类/对象外部和子类中不可访问

4.3命名规范

——应避免的名字

  • 在命名的时候永远不要使用字母‘l’(小写的L),‘O’(大写的O),或者‘I’(大写的I)作为单字符变量名。
    在有些字体里,这些字符无法和数字0和1区分,如果想用‘l’,用‘L’代替。

——Package and Module Names包名和模块名

  • 模块:模块应该用简短全小写的名字,如果为了提升可读性,下划线也是可以用的。
  • 包名:包名也应该使用简短全小写的名字,但不建议用下划线。
  • 当使用C或者C++编写了一个依赖于提供高级(更面向对象)接口的Python模块的扩展模块,这个C/C++模块需要一个下划线前缀(例如:_socket)

——Class Names类名

  • 类名一般使用首字母大写的约定。
  • 在接口被文档化并且主要被用于调用的情况下,可以使用函数的命名风格代替。
  • 注意,对于内置的变量命名有一个单独的约定:大部分内置变量是单个单词(或者两个单词连接在一起),首字母大写的命名法只用于异常名或者内部的常量。

——Exception Names 异常名

  • 因为异常一般都是类,所有类的命名方法在这里也适用。然而,你需要在异常名后面加上“Error”后缀(如果异常确实是一个错误)。

——Global Variable Names 全局变量名

  • (我们希望这一类变量只在模块内部使用。)约定和函数命名规则一样。
  • 注意:通过 from M import * 导入的模块应该使用all机制去防止内部的接口对外暴露,或者使用在全局变量前加下划线的方式(表明这些全局变量是模块内非公有)。

——Function Names 函数名

  • 函数名应该小写,如果想提高可读性可以用下划线分隔。

——Function and method arguments 函数和方法参数

  • 始终要将 self 作为实例方法的的第一个参数。
  • 始终要将 cls 作为类静态方法的第一个参数。
  • 如果函数的参数名和已有的关键词冲突,在最后加单一下划线比缩写或随意拼写更好。因此 class_ 比 clss 更好。(也许最好用同义词来避免这种冲突)

——Method Names and Instance Variables 方法名和实例变量

应遵循这样的函数命名规则:

  • 使用下划线分隔小写单词以提高可读性。
  • 在非共有方法和实例变量前使用单下划线。
  • 通过双下划线前缀触发Python的命名转换规则来避免和子类的命名冲突。

——Constants 常量

  • 定义在模块级
  • 通过下划线分隔的全大写字母命名。例如: MAX_OVERFLOW 和 TOTAL

5.其他建议

——和None进行比较

  • 和None进行比较的时候,应该始终使用is 或者 is not ,永远不要使用等号运算符
  • 使用is not 运算符,而不是 not ... is 。虽然功能完全相同,但前者更易于阅读
YES:
if foo is not None:

NO:
if not foo is None:

——富比较

  • 当使用富比较(rich comparisons,一种复杂的对象间比较的新机制,允许返回值不为-1,0,1)实现排序操作的时候,最好实现全部的六个操作符(__eq__, __ne__, __lt__, __gt__, __ge__)而不是依靠其他的代码去实现特定的比较。
YES:
def f(x): return 2*x

NO:
f = lambda x: 2*x

——True、False比较

  • 不要用 == 和True、False进行比较
正确: if greeting:
糟糕: if greeting == True:
更糟: if greeting is True:

——对象类型的比较

  • 对象类型的比较应该用isinstance()而不是直接比较type。
正确: if isinstance(obj, int):

糟糕: if type(obj) is type(1):

——对空序列的判断

  • 对于序列来说(strings,lists,tuples),可以使用空序列为false的情况。
正确: if not seq:
      if seq:

糟糕: if len(seq):
      if not len(seq):

——字符串切割检索

  • 使用 ”.startswith() 和 ”.endswith() 代替通过字符串切割的方法去检查前缀和后缀。
    startswith()和endswith()更干净,出错几率更小。
推荐: if foo.startswith('bar'):
糟糕: if foo[:3] == 'bar':

——try/except 语句

  • 当捕获到异常时,如果可以的话写上具体的异常名,而不是只用一个except: 块。
try:
    import platform_specific_module
except ImportError:
    platform_specific_module = None
  • 另外,对于所有的 try/except 语句块,在try语句中只填充必要的代码,这样能避免掩盖掉bug。
YES:
try:
    value = collection[key]
except KeyError:
    return key_not_found(key)
else:
    return handle_value(value)

NO:
try:
    # Too broad!
    return handle_value(collection[key])
except KeyError:
    # Will also catch KeyError raised by handle_value()
    return key_not_found(key)
  • 当代码片段局部使用了某个资源的时候,使用with 表达式来确保这个资源使用完后被清理干净。用try/finally也可以。

你可能感兴趣的:(Python代码规范PEP8总结)