Coding Conventions
正文
Indentation
use 4 spaces per indentation level - so 4 spaces on level one, 8 spaces on level two and so on. 推荐使用:
悬挂缩进
第一行只写到左括号,后续内容统一多缩进一级:
foo = long_function_name(
var_one,
var_two,
var_three,
var_four,
)
函数定义也是同样道理
def long_function_name(
var_one,
var_two,
var_three,
var_four,
):
print(var_one)
右括号与语句起始位置对齐。
Maximum Line Length
All lines should be up to 80 characters long; for lines containing comments or docstrings (to be covered later) the line length limit should be 73
表达式过长时推荐用()包裹, 不推荐用\
把下面这种格式作为默认规范:
if (
first_condition
and second_condition
):
do_something()
列表、函数调用、复杂表达式也采用同样原则:左括号后换行,内容缩进一级,右括号与语句起始位置对齐。
长表达式拆成多行时,把二元运算符放在下一行开头,而不是上一行末尾。
推荐写法:
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
)
Blank lines
1. 顶层函数和类之间空两行
“顶层”指直接定义在 Python 模块中,不属于其他类或函数。
import math
def calculate_area(radius):
return math.pi * radius**2
class Circle:
pass
def calculate_diameter(radius):
return radius * 2
这里:
-
import与第一个顶层定义之间有两行空行; -
顶层函数与类之间有两行空行;
-
两个顶层函数之间也应空两行。 标准库导入与项目内部导入之间保留一行空行即可:
import argparse
from inflammation import models, views
2. 类中的方法之间空一行
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return math.pi * self.radius**2
def diameter(self):
return self.radius * 2
类中的方法属于同一个类,关系更紧密,因此只空一行。
3. 函数内部可以少量使用空行
函数内部的空行用于划分逻辑阶段:
def process_records(records):
valid_records = [
record for record in records
if record.is_valid()
]
sorted_records = sorted(
valid_records,
key=lambda record: record.timestamp,
)
return generate_report(sorted_records)
推荐
def add_numbers(a, b):
result = a + b
return result
4. 装饰器与定义之间不要空行
@app.route("/users")
def get_users():
return users
White spaces
1. 括号内部不要加无意义空格
推荐:
my_function(colour[1], {id: 2})
不推荐:
my_function( colour[ 1 ], { id: 2 } )
2. 逗号、分号、冒号前不留空格
推荐:
print(x, y)
mapping = {"name": "Alice"}
不推荐:
print(x , y)
mapping = {"name" : "Alice"}
一般规律:
标点前无空格,标点后通常一个空格
3. 切片中的冒号是特殊情况
简单切片不加空格:
values[1:5]
values[:5]
values[1:]
matrix[:, 1]
复杂切片中,冒号可以近似看作低优先级二元运算符,两侧保持相同数量的空格:
values[start + offset : stop + offset]
而不要一边有、一边没有:
values[start + offset: stop + offset] # 不对称
8. 二元运算符两侧通常各一个空格
赋值运算符
x = 1
增强赋值
x += 1
total -= discount
比较运算符
x == 1
x != 1
x <= 10
成员运算符
item in collection
item not in collection
身份运算符
value is None
value is not None
布尔运算符
condition_a and condition_b
condition_a or condition_b
not condition_a
9. 普通赋值中的 = 两侧有空格
axis = "x"
angle = 90
size = 450
这里 = 表示执行赋值,因此两侧各一个空格。
10. 关键字参数中的 = 两侧不加空格
函数调用:
my_function(
1,
2,
axis=axis,
angle=angle,
size=size,
name=name,
)
这里的 axis=axis 不是普通赋值语句,而是在指定:
参数 axis 接收右侧 axis 变量的值
因此不加空格。
推荐:
draw(size=450, angle=90)
不推荐:
draw(size = 450, angle = 90)
11. 无类型注解的默认参数也不加空格
def draw(size=450, angle=90):
pass
但当参数包含类型注解时,PEP 8 推荐在默认值的 = 两侧加空格:
def draw(size: int = 450, angle: int = 90):
pass
对比:
def draw(size=450): # 无类型注解
pass
def draw(size: int = 450): # 有类型注解
pass
Naming Conventions
不同对象的推荐命名
变量:snake_case
变量名应说明它存储的具体内容。
推荐:
patient_name = "Alice"
temperature_readings = [36.5, 37.1]
number_of_records = 20
函数:snake_case,并使用动词
函数名应说明它执行什么操作:
calculate_average()
load_patient_records()
validate_user_input()
send_email()
类:PascalCase,并使用名词
类通常表示一种对象或概念,因此一般使用名词:
class PatientRecord:
pass
class TemperatureAnalyzer:
pass
class HTTPServerError(Exception):
pass
模块:简短、全小写
Python 文件名就是模块名:
models.py
analysis.py
data_loader.py
temperature_utils.py
可以使用下划线提高可读性:
data_processing.py
不推荐:
DataProcessing.py
patient-records.py
VeryLongModuleForProcessingPatientData.py
模块名不能使用连字符 -,因为它会被解释为减号,无法正常导入:
import data-processing # 错误
包:简短、全小写,尽量不用下划线
包是包含多个模块的目录:
inflammation/
datatools/
analytics/
PEP 8 对包名比模块名更倾向于简短连续的小写形式:
datatools
而不是:
data_tools
不过实际项目中带下划线的包名也很常见,仍应优先遵循项目规范。
实践中的推荐规则
| 对象 | 推荐风格 | 示例 |
|---|---|---|
| 变量 | snake_case | patient_name |
| 函数、方法 | snake_case | calculate_mean() |
| 常量 | UPPER_CASE | MAX_RETRIES |
| 类 | PascalCase | PatientRecord |
| 异常类 | PascalCase | InvalidDataError |
| 模块 | 全小写,可加下划线 | data_loader.py |
| 包 | 简短全小写 | datatools |
Comments
Block comment:块注释
块注释用于解释它后面的一段代码,并与这段代码保持相同缩进。
格式要求:
- 每行以
#开头; #后有一个空格;- 写成完整句子;
- 与所描述的代码处于相同缩进层级。
def calculate_discount(user):
# Premium users receive the historical discount rate to
# preserve compatibility with existing subscriptions.
discount_rate = 0.2 if user.is_premium else 0.1
return discount_rate
Inline comment:行内注释
行内注释放在语句末尾。
PEP 8 的格式是:
- 代码和注释之间至少两个空格;
- 以
#开头; - 谨慎使用。
retry_count += 1 # The first attempt is numbered zero.
行内注释适合解释非常局部、非常简短的特殊情况。
DocString
Google 风格
def fibonacci(n):
"""Calculate the nth Fibonacci number.
Args:
n: Index of the Fibonacci number.
Returns:
The nth Fibonacci number.
Raises:
ValueError: If n is negative.
"""