python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python文档字符串

Python中函数文档字符串docstring的编写规范详解

作者:星河耀银海

Python函数文档字符串(docstring)是代码的重要组成部分,它作为函数的使用说明书帮助开发者理解函数功能,本文详解介绍了Python文档字符串的规范,三大风格对比及实战技巧,帮你轻松提升代码可读性,告别协作时的沟通成本

一、开篇:代码是写给人看的

好的代码自己会说话,而docstring(文档字符串)就是帮代码"说话"的工具。一个函数如果没有docstring,调用者就只能去读源码或者猜它的用法。

对比有和没有docstring的区别:

# ❌ 没有docstring——只能猜
def calc(a, b, mode=1):
    if mode == 1:
        return a + b
    elif mode == 2:
        return a - b
    else:
        return a * b

# ✅ 有docstring——一目了然
def calc(a: float, b: float, mode: int = 1) -> float:
    """对两个数执行指定的运算。

    Args:
        a: 第一个操作数
        b: 第二个操作数
        mode: 运算模式,1=加法,2=减法,其他=乘法

    Returns:
        运算结果

    Raises:
        TypeError: 当操作数不是数字时
    """
    if mode == 1:
        return a + b
    elif mode == 2:
        return a - b
    else:
        return a * b

docstring是函数、类、模块的"使用说明书"。更重要的是,Python的help()函数和众多文档生成工具都依赖docstring。写好docstring,是对自己(三个月后的你)和同事最大的善意。

二、docstring的基本规则

2.1 位置和格式

# docstring的基本规则:
# 1. 放在函数/类/模块的第一行(def/class之后的第一条语句)
# 2. 用三引号包裹("""或''')
# 3. 可以使用多行

def greet(name: str) -> str:
    """向指定的人打招呼。"""
    return f"你好,{name}!"

# 访问docstring
print(greet.__doc__)  # 向指定的人打招呼。

# help()查看——更友好的展示
# help(greet)
# 输出:
# Help on function greet in module __main__:
#
# greet(name: str) -> str
#     向指定的人打招呼。

# ⚠️ docstring必须是字符串字面量,不能是变量
# def bad():
#     doc = "文档"   # 这不是docstring!是普通的字符串赋值
#     pass

2.2 单行docstring

# 适用场景:函数功能简单明了

def add(a: int, b: int) -> int:
    """返回a和b的和。"""
    return a + b

def is_even(n: int) -> bool:
    """判断一个整数是否为偶数。"""
    return n % 2 == 0

# PEP 257规范:
# - 三引号在同一行开始和结束
# - 使用句号结尾
# - 描述函数的功能(做什么),而不是实现(怎么做)
# - 使用命令式语气:"返回..."而不是"这个函数返回..."

2.3 多行docstring

# 适用场景:函数逻辑复杂,需要详细说明

def fetch_user_data(
    user_id: int,
    fields: list[str] | None = None,
    include_inactive: bool = False,
    timeout: int = 30
) -> dict | None:
    """从数据库获取用户数据。

    根据用户ID查询用户信息。如果提供了fields参数,
    只返回指定的字段。默认不包含已停用的用户。

    Args:
        user_id: 用户唯一标识符
        fields: 需要返回的字段列表,None表示返回所有字段
        include_inactive: 是否包含已停用的用户
        timeout: 查询超时时间(秒)

    Returns:
        包含用户数据的字典,如果用户不存在则返回None。
        字典的键取决于fields参数。

    Raises:
        ValueError: 当user_id小于等于0时
        TimeoutError: 查询超时时
        DatabaseError: 数据库连接失败时

    Examples:
        >>> fetch_user_data(123)
        {'name': '张三', 'email': 'zs@test.com', 'age': 25}

        >>> fetch_user_data(123, fields=['name', 'age'])
        {'name': '张三', 'age': 25}

        >>> fetch_user_data(999)
        None
    """
    if user_id <= 0:
        raise ValueError("user_id必须大于0")
    # ... 实际实现 ...
    return {"name": "张三", "email": "zs@test.com", "age": 25}

三、三大docstring风格对比

3.1 Google风格(推荐!)

def send_notification(
    user: str,
    message: str,
    *,
    channel: str = "email",
    priority: str = "normal",
    attachments: list[str] | None = None,
    retry_count: int = 3
) -> bool:
    """向用户发送通知消息。

    支持多种通知渠道,消息发送失败时自动重试。
    高优先级消息会绕过用户的免打扰设置。

    Args:
        user: 接收通知的用户名或用户ID
        message: 通知内容,支持纯文本
        channel: 通知渠道,可选值:\"email\"、\"sms\"、\"push\"、
            \"wechat\"。(默认:\"email\")
        priority: 优先级,可选值:\"low\"、\"normal\"、\"high\"、
            \"urgent\"。(默认:\"normal\")
        attachments: 附件文件路径列表,None表示无附件
            (默认:None)
        retry_count: 失败重试次数(默认:3)

    Returns:
        True表示发送成功,False表示所有重试均失败。

    Raises:
        ValueError: 当channel或priority值不合法时
        FileNotFoundError: 当附件文件不存在时

    Example:
        >>> send_notification("张三", "您的订单已发货",
        ...                   channel="sms", priority="high")
        True

        >>> send_notification("李四", "服务器告警",
        ...                   channel="push", priority="urgent")
        True
    """
    valid_channels = {"email", "sms", "push", "wechat"}
    if channel not in valid_channels:
        raise ValueError(f"无效的通知渠道: {channel}")
    # ... 实际实现 ...
    return True

3.2 NumPy风格

def calculate_statistics(
    data: list[float],
    *,
    skip_na: bool = True,
    percentiles: list[int] | None = None
) -> dict:
    """计算数据集的描述性统计。

    Parameters
    ----------
    data : list of float
        待分析的数据列表。
    skip_na : bool, optional
        是否跳过NaN值。默认值为True。
    percentiles : list of int or None, optional
        需要计算的百分位数列表。默认值为None,
        不计算百分位数。

    Returns
    -------
    dict
        包含统计结果的字典,包含以下键:
        - "count": 样本数量
        - "mean": 平均值
        - "std": 标准差
        - "min": 最小值
        - "max": 最大值
        - "percentiles": 百分位数结果(如果指定了percentiles)

    Raises
    ------
    ValueError
        当data为空列表时。

    Examples
    --------
    >>> calculate_statistics([1.0, 2.0, 3.0, 4.0, 5.0])
    {'count': 5, 'mean': 3.0, 'std': 1.58, 'min': 1.0, 'max': 5.0}
    """
    pass

3.3 Sphinx/reStructuredText风格

def validate_email(email: str) -> bool:
    """验证邮箱地址格式是否合法。

    :param email: 待验证的邮箱地址字符串
    :type email: str
    :return: 邮箱格式合法返回True,否则返回False
    :rtype: bool
    :raises TypeError: 当email不是字符串时

    验证规则:
    1. 包含恰好一个 @ 符号
    2. @ 前后都有字符
    3. @ 后面部分包含一个 .

    ::

        >>> validate_email("user@example.com")
        True
        >>> validate_email("invalid-email")
        False
    """
    if not isinstance(email, str):
        raise TypeError("email必须是字符串")
    parts = email.split("@")
    return len(parts) == 2 and all(parts) and "." in parts[1]

3.4 风格选型建议

# 💡 风格选择建议:
# 
# Google风格 → 推荐!最流行,可读性最好,VS Code/PyCharm原生支持
# NumPy风格 → 科学计算/数据分析项目首选
# Sphinx风格 → 用Sphinx生成文档的项目,传统选择
#
# 关键不是用哪种风格,而是在项目中保持一致!

四、docstring在实际开发中的应用

4.1 doctest:用docstring做测试

# doctest模块可以从docstring中提取>>>示例并自动测试!

def add(a: int, b: int) -> int:
    """返回两个整数的和。

    >>> add(2, 3)
    5
    >>> add(-1, 1)
    0
    >>> add(0, 0)
    0
    """
    return a + b

def factorial(n: int) -> int:
    """计算n的阶乘。

    >>> factorial(0)
    1
    >>> factorial(1)
    1
    >>> factorial(5)
    120
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n必须是非负整数
    """
    if n < 0:
        raise ValueError("n必须是非负整数")
    if n <= 1:
        return 1
    return n * factorial(n - 1)

# 运行doctest
if __name__ == "__main__":
    import doctest
    doctest.testmod()
    print("所有doctest通过!")

4.2 模块和类的docstring

"""
用户管理模块

提供用户注册、登录、信息查询和管理功能。

Classes:
    User: 用户数据模型
    UserManager: 用户管理服务
    AuthenticationError: 认证异常

Functions:
    create_user: 创建新用户
    authenticate: 验证用户身份

Usage:
    >>> from user_management import create_user
    >>> user = create_user("zhangsan", "password123",
    ...                    email="zs@test.com")
    >>> print(user.name)
    张三
"""

class UserManager:
    """用户管理服务类。

    负责处理用户的创建、查询、更新和删除操作。
    所有数据库操作通过此类统一管理。

    Attributes:
        db_connection: 数据库连接对象
        cache: 用户信息缓存
        max_cache_size: 最大缓存条目数

    Example:
        >>> manager = UserManager(db_conn)
        >>> user = manager.get_user(123)
        >>> manager.update_user(123, {"age": 30})
    """
    def __init__(self, db_connection):
        """初始化用户管理器。"""
        pass

五、总结

docstring是程序员给未来的自己(和同事)写的信。好的docstring让代码"自带说明书"。

核心要点:

  1. 所有公共函数/类/模块都应该有docstring
  2. PEP 257是Python docstring的官方规范
  3. Google风格是目前最流行的选择
  4. doctest让docstring既是文档又是测试
  5. 一致性比风格更重要——项目内统一风格

docstring应该写什么:

docstring不应该写什么:

以上就是Python中函数文档字符串docstring的编写规范详解的详细内容,更多关于Python文档字符串的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文