你写完一个函数,过两周再看------参数是什么意思?返回什么类型?有没有副作用?完全想不起来。
好的 docstring 就是一份「随时可查的说明书」。这篇文章教你从零写出规范的 Python 文档字符串,不仅自己看得懂,团队协作和 IDE 提示也能直接用上。
一、docstring 是什么?
docstring 就是函数、类、模块第一行写的字符串,Python 会自动把它当作文档保存起来。
python
def add(a, b):
"""返回两个数的和。"""
return a + b
# 随时可以查看
print(add.__doc__)
# 输出:返回两个数的和。
# help() 也能直接看到
help(add)
看起来很简单,但写什么样的 docstring 、写多少细节 、用什么格式,这些才是真正拉开差距的地方。
二、docstring 的基本规则
2.1 位置要求
docstring 必须是函数/类/模块的第一条语句,紧跟在定义行之后:
python
# ✅ 正确
def process(data):
"""处理输入数据。"""
...
# ❌ 错误:docstring 之前有其他代码
def process(data):
x = 1 # ← 这行在 docstring 前面,不行
"""处理输入数据。"""
...
2.2 引号选择
三引号,单引号双引号都行,团队里保持一致即可:
python
def func():
"""三双引号,最常用。"""
pass
def func():
'''三单引号,也行。'''
pass
2.3 多行写法
一行放得下就一行,放不下就换行:
python
# 单行:简短描述就行
def max_value(items):
"""返回列表中的最大值。"""
pass
# 多行:第一行概述,空一行,写详细说明
def max_value(items):
"""
返回列表中的最大值。
如果列表为空,返回 None。
Args:
items: 数字列表。
Returns:
列表中的最大值,或 None。
"""
pass
格式约定:单行 docstring 不加首尾空行,多行 docstring 第一行概述 + 空一行 + 详细内容。
三、四大主流 docstring 风格,选一种坚持用
Python 社区没有「官方强制标准」,但有几种主流风格。选哪种不重要,重要的是全项目统一。
3.1 Google 风格(推荐)
python
def calculate_area(width, height):
"""
计算矩形的面积。
Args:
width (float): 矩形的宽度,必须大于 0。
height (float): 矩形的高度,必须大于 0。
Returns:
float: 矩形的面积。
Raises:
ValueError: 当 width 或 height 小于等于 0 时抛出。
Examples:
>>> calculate_area(3, 4)
12.0
"""
if width <= 0 or height <= 0:
raise ValueError("宽度和高度必须大于 0")
return width * height
优点:可读性好,结构清晰,被 TensorFlow、PyTorch 等主流项目采用。
3.2 NumPy 风格
python
def calculate_area(width, height):
"""
计算矩形的面积。
Parameters
----------
width : float
矩形的宽度,必须大于 0。
height : float
矩形的高度,必须大于 0。
Returns
-------
float
矩形的面积。
Raises
------
ValueError
当 width 或 height 小于等于 0 时抛出。
Examples
--------
>>> calculate_area(3, 4)
12.0
"""
if width <= 0 or height <= 0:
raise ValueError("宽度和高度必须大于 0")
return width * height
优点 :科学计算领域的主流风格,NumPy、SciPy、Pandas 都在用。--- 分隔线在纯文本下视觉更清晰。
3.3 reST(Sphinx)风格
python
def calculate_area(width, height):
"""
计算矩形的面积。
:param width: 矩形的宽度,必须大于 0
:type width: float
:param height: 矩形的高度,必须大于 0
:type height: float
:returns: 矩形的面积
:rtype: float
:raises ValueError: 当 width 或 height 小于等于 0 时抛出
"""
if width <= 0 or height <= 0:
raise ValueError("宽度和高度必须大于 0")
return width * height
优点:Sphinx 文档工具原生支持,适合需要生成 HTML/PDF 文档的大型项目。
3.4 风格对比速查表
| 对比项 | NumPy | reST | |
|---|---|---|---|
| 可读性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 排版简洁度 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 适合场景 | 通用项目 | 科学计算 | 需 Sphinx 生成文档 |
| 代表项目 | TensorFlow、PyTorch | NumPy、Pandas | Django(部分) |
建议 :新手直接选 Google 风格,清晰易懂,覆盖面最广。
四、每个部分该怎么写
一个完整的 docstring 通常包含以下几个部分,按需选用,别全抄。
4.1 概述(必写)
第一行,一句话说明这个函数做什么,不是怎么做。
python
# ✅ 好:说明做什么
def fetch_data(url):
"""从指定 URL 获取 JSON 数据并返回字典。"""
pass
# ❌ 差:在说怎么做,不是做什么
def fetch_data(url):
"""使用 requests 库发送 GET 请求,解析 JSON 返回值。"""
pass
4.2 Args / Parameters(有参数就写)
说明每个参数的含义和类型:
python
def search_users(name=None, age_min=0, role="member"):
"""
搜索符合条件的用户。
Args:
name (str, optional): 用户名关键字,支持模糊匹配。默认为 None。
age_min (int): 最小年龄,默认为 0。
role (str): 用户角色,可选值为 member、admin、superadmin。
"""
pass
要点:
- 写类型 + 含义 + 可选值/默认值
optional标注有默认值的参数- 一个参数占一行
4.3 Returns(有返回值就写)
说明返回值的类型和含义:
python
def get_user_info(user_id):
"""
获取用户信息。
Args:
user_id (int): 用户 ID。
Returns:
dict: 用户信息字典,包含以下字段:
- name (str): 用户名
- email (str): 邮箱
- role (str): 角色
如果用户不存在,返回 None。
"""
pass
要点:
- 如果返回多种类型,用
Union[str, None]或写清楚各条件 - 返回复杂结构时,列出字段说明
4.4 Raises(有异常就写)
说明函数可能抛出的异常:
python
def divide(a, b):
"""
计算两数之商。
Args:
a (float): 被除数。
b (float): 除数,不能为 0。
Returns:
float: 两数之商。
Raises:
ZeroDivisionError: 当 b 为 0 时抛出。
TypeError: 当 a 或 b 不是数字类型时抛出。
"""
return a / b
要点:
- 只写函数主动抛出的异常,不写 Python 内部可能抛出的
ValueError、TypeError是最常见的两类
4.5 Examples(强烈建议写)
给一个可运行的示例,比一大段描述管用:
python
def format_price(amount, currency="CNY"):
"""
格式化价格显示。
Args:
amount (float): 金额。
currency (str): 货币代码,默认为 CNY。
Returns:
str: 格式化后的价格字符串。
Examples:
>>> format_price(99.9)
'¥99.90'
>>> format_price(49.5, currency="USD")
'$49.50'
"""
pass
有 Examples 的 docstring,可以直接用
doctest模块自动跑测试,一举两得。
4.6 Notes / See Also(按需写)
python
def train_model(data, epochs=100):
"""
训练文本分类模型。
Args:
data (pd.DataFrame): 训练数据。
epochs (int): 训练轮数。
Returns:
Model: 训练好的模型对象。
Note:
使用预训练的 BERT-base 作为编码器。
数据量少于 1000 条时建议减少 epochs。
See Also:
evaluate_model: 模型评估函数
save_model: 模型保存函数
"""
pass
五、不同场景的 docstring 示例
5.1 简单工具函数
python
def is_palindrome(s):
"""
判断字符串是否为回文(忽略大小写和空格)。
Args:
s (str): 待判断的字符串。
Returns:
bool: 是回文返回 True,否则返回 False。
Examples:
>>> is_palindrome("racecar")
True
>>> is_palindrome("hello")
False
>>> is_palindrome("A man a plan a canal Panama")
True
"""
cleaned = s.lower().replace(" ", "")
return cleaned == cleaned[::-1]
5.2 类的 docstring
python
class DataLoader:
"""
数据加载与预处理工具类。
支持从 CSV、JSON、Parquet 格式加载数据,
并提供缺失值填充、类型转换等预处理功能。
Attributes:
data (pd.DataFrame): 加载后的数据。
filepath (str): 数据文件路径。
encoding (str): 文件编码格式。
Examples:
>>> loader = DataLoader("data.csv", encoding="gbk")
>>> loader.load()
>>> loader.info()
"""
def __init__(self, filepath, encoding="utf-8"):
"""初始化数据加载器。
Args:
filepath (str): 数据文件路径。
encoding (str): 文件编码,默认为 utf-8。
"""
self.filepath = filepath
self.encoding = encoding
self.data = None
5.3 带类型注解的函数(推荐)
docstring + 类型注解双保险,IDE 提示最完整:
python
from typing import Optional, List, Dict
def get_top_users(
data: List[Dict[str, object]],
n: int = 10,
sort_by: str = "score",
ascending: bool = False
) -> List[Dict[str, object]]:
"""
获取排名前 N 的用户。
Args:
data: 用户数据列表,每个元素是包含用户信息的字典。
n: 返回的用户数量,默认为 10。
sort_by: 排序字段名,默认为 score。
ascending: 是否升序排列,默认为 False(降序)。
Returns:
排序后的前 N 个用户数据列表。
Raises:
KeyError: 当 sort_by 指定的字段不存在时抛出。
ValueError: 当 n 小于 1 时抛出。
"""
pass
类型注解写在函数签名里,docstring 重点写业务含义,不要重复写类型。
六、模块级 docstring
每个 Python 文件顶部也应该写 docstring,说明这个模块是做什么的:
python
"""
数据处理工具模块。
提供数据清洗、格式转换、缺失值处理等常用功能。
主要服务于用户行为分析项目。
模块依赖:
- pandas >= 1.5
- numpy >= 1.23
使用方式:
from data_utils import clean_dataframe, parse_dates
df = clean_dataframe(raw_data)
"""
七、docstring 和注释的区别
这是很多人搞混的点:
python
def calculate_discount(price, level):
"""
根据用户等级计算折扣价格。
Args:
price (float): 原价。
level (str): 用户等级,可选 gold、silver、bronze。
Returns:
float: 折后价格。
"""
# VIP 等级使用不同的折扣率(这是注释,解释实现逻辑)
discount_map = {
"gold": 0.7, # 金牌会员 7 折
"silver": 0.85, # 银牌会员 85 折
"bronze": 0.95, # 铜牌会员 95 折
}
# 如果等级不存在,不打折(这是注释,说明边界情况)
rate = discount_map.get(level, 1.0)
return price * rate
| 对比 | docstring | 注释 |
|---|---|---|
| 写给谁看 | 使用这个函数的人 | 维护这段代码的人 |
| 写什么 | 做什么、参数、返回值 | 为什么这么写 |
| 位置 | 函数/类/模块的第一行 | 代码内部的任意位置 |
能否被 help() 查看 |
✅ 可以 | ❌ 不行 |
一句话:docstring 写「接口说明」,注释写「实现逻辑」。
八、自动化工具:让规范不再靠自觉
光靠人肉规范不靠谱,用工具自动检查和生成。
8.1 pydoc:Python 自带文档生成
bash
# 命令行查看文档
pydoc your_module
# 生成 HTML 文档
pydoc -w your_module
8.2 Sphinx:专业文档生成工具
bash
pip install sphinx
# 在项目目录下初始化
sphinx-quickstart
# 自动从 docstring 生成 API 文档
sphinx-apidoc -o docs/ src/
NumPy、Pandas、Matplotlib 的官方文档都是 Sphinx 生成的。
8.3 docformatter:自动格式化 docstring
bash
pip install docformatter
# 自动格式化
docformatter --in-place your_file.py
8.4 pydocstyle:检查 docstring 规范
bash
pip install pydocstyle
# 检查所有 Python 文件
pydocstyle src/
# 检查单个文件
pydocstyle utils.py
推荐 :把
pydocstyle加入 pre-commit hook 或 CI 流水线,不规范直接报错,逼着团队遵守规范。
九、写好 docstring 的 5 个原则
- 说做什么,不说怎么做------docstring 是给调用者看的,不是给自己的代码笔记
- 有参数就写参数,有返回就写返回------别偷懒,这些是最常用的信息
- 给 Examples------一段可运行的示例比三段描述管用,还能当测试用
- 和类型注解配合------类型交给注解,业务含义交给 docstring,别重复
- 风格统一------一个项目只选一种风格,别这个函数 Google 风格那个函数 NumPy 风格
写 docstring 不是浪费时间,是在给未来的自己和队友省时间。养成习惯,你会感谢现在写了 docstring 的自己。