一、布局
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