一、布局
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(): passclass Demo1(): def method1(self): pass def method2(self): passdef func2(): passclass 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