一、布局

1.1 缩进

  • 每一级缩进使用4个空格
  • 类似定义函数或者调用函数时参数过多的场景,有两种推荐缩进做法,一种是第一行有参数,换行后利用括号默认的垂直对齐方式。另一种方式就是第一行没有参数,参数直接换行到下一行,此时缩进需要比其他代码多缩进一级,便于轻松识别出不是其他的代码语句
  • if语句中条件比较多需要换行时,推荐两种处理方式,一种是判断条件和代码之间增加一行注释,另外一种就是对条件做更多一层的缩进,从而用于语句块中的代码区分开
  • 当多行结构中使用的括号(小括号、方括号、花括号)的右括号另起一行的时候,可以与上一行的第一个字符对齐
    或者也可以与下一行的第一个字符对齐
# 以下代码为推荐代码:
def long_function_name(var_one,
                   var_two, 
                   var_three,
                   var_four):
    print(var_one)

def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

foo = long_function_name(var_one, var_two,
                     var_three, var_four)

foo = long_function_name(
    var_one, var_two,
    var_three, var_four)

if (this_is_one_thing and
    that_is_another_thing):
    # 当满足某种条件时执行此分支.
    do_something()

if (this_is_one_thing
        and that_is_another_thing):
    do_something()

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',
)

# 以下代码为不推荐代码
def long_function_name(var_one,
    var_two,var_three,var_four):
    print(var_one)

foo = long_function_name(var_one, var_two,
    var_three, var_four)
    
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

1.2 Tabs 键还是 空格键

  • 空格是首选的缩进方式
  • 如果使用tab键则所有缩进均需要使用tab键
  • python3不允许同时使用空格和tab键

1.3 行最大长度

  • 所有行限制最大字符数为79
  • 注释、字符串等文本行最大字符数限制72
  • 如果团队内达成一致认识,可以将代码行最大长度扩大到99,注释行仍然限制72
  • 一行代码过长时优先通过小括号,方括号,花括号来换行,而不是反斜线的方式
# 推荐做法
def methond_to_show_code_set_in_multiline_with_bracket(first_paramp="",
                                                  second_param="",
                                                  third_param=""):
   pass
# 不推荐做法
def methond_to_show_code_set_in_multiline_with_bracket(first_paramp="",\
                                                  second_param="",\
                                                  third_param=""):
   pass

1.4 在二元运算符之前还是之后换行呢?

  • 在很长的表示式中如果想换行推荐在二元操作符之前换行
# 推荐做法
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.5 空行

  • 文件顶级的类或者函数定义的前后需要使用两个空行
  • 类中方法定义前后使用一个空行
# 注释

def func1():
    pass


class Demo1():

    def method1(self):
    pass

    def method2(self):
    pass


def func2():
    pass


class Demo2():
    pass

1.6 源文件编码

  • 文件中不应有编码声明,默认均以UTF-8编码

1.7 imports

  • 不同的包在不同的行导入,不推荐一行导入多个包
  • 一行可以导入同一个包中的多个模块或类
  • 导入总是文件的顶部,在模块注释和文档字符串之后,在模块的全局变量和常量之前
  • 导入应该按照如顺序导入,在每一组中间需要加入空行
  • 标准库导入
  • 第三方库导入
  • 本地应用库导入
  • 推荐使用绝对路径导入,可读性更好
  • 避免使用通配符导入,如from xxx import *
# 推荐做法
import os
import sys
from subprocess import Popen, PIPE

from flask import Flask

# 不推荐做法
import os,sys
from subprocess import Popen, PIPE
from flask import Flask

1.8 模块级的魔法函数名

  • 像 all,author,version等模块级的魔法函数,应该放在文档字符串后面,并且在除了from future import xxx 语句以外其他的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

二、字符串引号

  • 单引号或者双引号均可以,只需要代码风格保持一致即可
  • 三引号推荐使用三个双引号

三、表达式和语句块中的空格

3.1 不能忍受的

  • 下列情况下不允许使用空格

    • 紧跟在小括号、中括号、大括号后
    • 紧贴在逗号,分号或者冒号之前,注意在切片中的冒号,两边需要有相同数量的空格,当切片参数省略时,空格也必须省略
    • 紧贴在函数参数的左括号之前
    • 紧贴索引或者切片的左括号之前
    • 为了和赋值运算符对齐,在赋值运算符之前加多个空格
# 推荐做法
spam(ham[1], {eggs: 2})
if x == 4: print x, y; x, y = y, x
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]
spam(1)
dct['key'] = lst[index]
x = 1
y = 2
long_variable = 3

# 不推荐做法
spam( ham[ 1 ], { eggs: 2 } )
if x == 4 : print x , y ; x , y = y , x
ham[lower   offset:upper   offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : upper]
ham[ : upper]
spam (1)
dct ['key'] = lst [index]
x             = 1
y             = 2
long_variable = 3

3.2 其他建议

  • 避免在尾部添加空格
  • 总是在二元运算符两天各添加一个空格
  • 如果使用具有不同优先级的运算符,推荐在具有最低优先级的运算符周围加空格,但是最多使用一个空格,并且在二元运算符两边使用相同数量的空格
  • 在函数调用或定义中使用默认值或者指定参数的时候,=前后不要使用空格
  • 功能型注释应该使用冒号的一般性原则,并且在使用->的时候前后需要使用空格
  • 当给有类型备注的参数赋值的时候,在=两边添加空格,注意这里仅针对有类型备注说明的
  • 复合语句(一行中有多个语句)通常是不允许的
# 推荐做法
i = i   1
submitted  = 1
x = x*2 - 1
hypot2 = x*x   y*y
c = (a b) * (a-b)
def complex(real, imag=0.0):
   return magic(r=real, i=imag)
def munge(input: AnyStr): ...
def munge() -> AnyStr: ...
def munge(sep: AnyStr = None): ...
def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...
if foo == 'blah':
   do_blah_thing()
do_one()
do_two()
do_three()

# 不推荐做法
i=i 1
submitted  =1
x = x * 2 - 1
hypot2 = x * x   y * y
c = (a   b) * (a - b)
def complex(real, imag = 0.0):
   return magic(r = real, i = imag)
def munge(input:AnyStr): ...
def munge()->PosInt: ...
def munge(input: AnyStr=None): ...
def munge(input: AnyStr, limit = 1000): ...
if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()

四、注释

4.1 注释说明:

  • 与代码相矛盾的注释比没有注释更糟糕,当代码更改时,优先更新对应的注释
  • 注释应该是完整的句子,如果一个注释是一个短语或句子,它的第一个单词应该大写
  • 注释中永远不要改变标识符的大小写
  • 如果注释很短,结尾的句号可以省略
  • 块注释一般由完整句子的一个或者多个段落组成,并且每句话结束有个句号
  • 在句尾结束的时候应该使用两个空格
  • 在非英语国家的python程序员,请使用英语写注释,除非120%的确定你的代码不会被其他语言的人阅读

4.2 块注释

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

4.3 行注释

  • 有节制的使用行注释
  • 行注释是与代码同行的注释,行注释和代码之间至少两个空格分隔
  • 行注释由一个#和一个空格开始

4.4 文档注释

  • 要为所有的公共模块、函数、类以及方法编写文档说明,非公共的方法没有必要,但是应该有一个描述方法具体作用的注释,这个注释在def那一行之后
  • 多行文档注释的结尾的三个引号需要独自成一行
  • 对于单行的文档注释,结尾的三个引号应该和文档在一行

五、命名规范

5.1 最重要的原则

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

5.2 命名风格

  • lower_case_with_underscores 使用下划线分割的小写字母
  • CapitalizadWords 驼峰命名法
  • mixedCase 第一个单词的首字母小写
  • lowercase 小写字母
  • UPPERCASE 大写字母
  • UPPER_CASE_WITH_UNDERSCORES 使用下划线分割的大写字母
  • b 单个小写字母
  • B 单个大写字母
  • Capitalized_Words_With_Underscores(巨丑)

5.3 命名约定

5.3.1 应避免的命名

  • 永远不要使用实木’l’(小写的L),‘O’(大写的o)或者I(大写的i)作为单字符变量名

5.3.2 包和模块命名

  • 模块名应该用简短全小写的名字,如果为了提升可读性,下划线也是可以的
  • 包名也应该使用简短全小写的名字,不建议使用下划线

5.3.3 类命名

  • 类名一般使用首字母大写的约定

5.3.4 异常命名

  • 异常一般都是类,所以使用类名约定,此外需要在异常名后加上‘Error’后缀

5.3.5 全局变量命名

  • 全局变量名应该小写,如果为了提高可读性,可以使用下划线

5.3.6 函数名命名

  • 函数名应该小写,如果为了提高可读性,可以使用下划线

5.3.7 函数和方法的参数命名

  • 和普通的变量名一致,即小写,如果为了提高可读性,可以使用下划线

5.3.8 方法名和实例变量命名

  • 方法名和函数名一致,可以使用下划线
  • 非公有方法名以单下划线开头
  • 实例变量使用单下划线开头

5.3.9 常量命名

  • 通过下划线分割的全大写字母,如 MAX_OVERFLOW

5.3.10 继承设计

  • 公共属性不应该有前缀下划线
  • 如果不确定一个属性时公有还是非公有,选择非公有,因为非公有转换为公有比
  • 反过来简单的多
  • 对于单一的公有属性数据,最好直接暴露它的变量名
  • 不希望子类使用的属性,使用双下划线开头

5.4 公共和内部接口

  • 为了更好的支持自省,模块应该使用all,属性显式的在他们的公共API中声明
  • 即使通过all设置过,内部接口(包,模块,类,方法,属性或其他名字)依然需要单个下划线前缀

六、编码建议

  • 代码应该用不损害其他Python实现的方式编写
  • 和像None这样的单例对象进行比较的时候应该使用is 或者is not ,永远不要使用等号运算符
  • 始终使用def表达式,而不是通过赋值语句将lambda表达式绑定到一个变量上
  • 从Exception继承异常,而不是BaseException,直接继承BaseException的异常适用于几乎不用来捕捉的异常
  • 返回的语句保持一致
  • 当代码片段局部使用了某个资源的时候,使用with 表达式来确保这个资源使用完后被清理干净
  • 使用 ”.startswith() 和 ”.endswith() 代替通过字符串切割的方法去检查前缀和后缀
  • 对象类型的比较应该用isinstance()而不是直接比较type
  • 不要用 == 去和True或者False比较
# 推荐:
if foo is not None:
def f(x): return 2*x

# 不推荐:
if not foo is None:
f = lambda x: 2*x
最后修改:2022 年 05 月 11 日
如果觉得我的文章对你有用,请随意赞赏