ZetCode

Python 注释和文档字符串

最后修改于 2025 年 4 月 2 日

注释和文档字符串对于记录 Python 代码至关重要。注释用于解释实现细节,而文档字符串则描述用法和功能。本指南涵盖了从基本语法到文档生成的所有方面。正确的文档可以提高代码的可维护性,并启用自动生成文档的工具。学习如何遵循 Python 最佳实践来编写清晰有效的注释和文档字符串。

单行注释

单行注释以 # 符号开头,并一直持续到行尾。它们用于简短的解释和行内注释。此示例展示了正确的单行注释用法。有效的注释解释的是“为什么”,而不是“是什么”——代码本身就显示了正在做什么。

single_line.py
# Calculate circle area (single-line comment before code)
def circle_area(radius):
    return 3.14159 * radius ** 2  # Using approximate value of π

# Bad example: Redundant comment
x = x + 1  # Increment x by 1

# Good example: Explains non-obvious logic
# Adjust for edge case when divisor is near zero
if abs(divisor) < 1e-10:
    result = float('inf')

# Additional example: Commented-out code (use sparingly)
# old_value = calculate_old_way()  # Deprecated 2024-01-15
new_value = calculate_new_way()

# Additional example: End-of-line comments
names = ["Alice", "Bob", "Charlie"]  # List of user names

第一个注释解释了函数的作用,而行内注释则说明了 π 的近似值。避免冗余的注释,这些注释只是重复代码明显做了什么。相反,请记录非显而易见实现的根本原因。

通常应删除被注释掉的代码(请使用版本控制),但当暂时保留时,请包含弃用说明。行尾注释应简短,并且仅在真正有助于理解该特定行时使用。

多行注释

Python 没有真正的多行注释语法,但可以使用连续的单行注释或三引号字符串进行较长的解释。此示例展示了这两种方法。多行解释对于复杂的算法或模块级文档非常有用。

multi_line.py
"""
This is technically a string, not a comment,
but often used for module-level documentation.
It can span multiple lines and is ignored when
not assigned to a variable.
"""

# This is the preferred way for actual comments
# that span multiple lines in Python. Each line
# starts with a # and the comment is clearly
# distinguished from docstrings.

def complex_algorithm(data):
    # Phase 1: Data preprocessing
    # - Normalize input values
    # - Handle missing data
    # - Convert categorical variables
    
    # Phase 2: Core calculation
    # Uses the Smith-Waterman algorithm
    # with custom modifications for our use case
    
    pass

# Additional example: Block comment before code
###########################################
# Database Connection Handler             #
# Manages connection pooling and retries  #
###########################################
class DatabaseHandler:
    pass

顶部的三引号字符串实际上是一个字符串字面量,但当它未赋值给变量时,它就像注释一样工作。对于实际的多行注释,首选连续的单行注释,因为它们是明确的注释。

complex_algorithm 函数展示了如何构建关于多阶段过程的详细解释。分节标题(如数据库处理器的示例)可以谨慎使用时帮助组织大型代码文件。

函数文档字符串

文档字符串是出现在模块、函数、类和方法中的第一个语句的字符串字面量。它们遵循 PEP 257 约定,并描述对象的作用和用法。此示例演示了正确的函数文档字符串格式。良好的文档字符串可以启用自动生成文档,并帮助 help() 和 IDE 等工具。

function_docstrings.py
def calculate_interest(principal, rate, years):
    """Calculate compound interest.
    
    Args:
        principal (float): Initial investment amount
        rate (float): Annual interest rate (e.g., 0.05 for 5%)
        years (int): Investment period in years
    
    Returns:
        float: Final amount after compound interest
    
    Examples:
        >>> calculate_interest(1000, 0.05, 10)
        1628.894626777442
    """
    return principal * (1 + rate) ** years

# Additional example: One-line docstring
def greet(name):
    """Return a greeting string for the given name."""
    return f"Hello, {name}!"

# Additional example: Multi-class function
def process_data(data, verbose=False):
    """Process input data with optional verbosity.
    
    Performs data cleaning, normalization, and feature extraction
    in a single pipeline.
    
    Parameters:
        data (DataFrame): Input dataset
        verbose (bool): If True, print progress messages
    
    Raises:
        ValueError: If data contains invalid values
    
    Note:
        This function modifies the input DataFrame in place.
    """
    # Implementation here
    pass

calculate_interest 文档字符串遵循流行的 Google 风格,具有清晰的参数、返回值和示例部分。单行文档字符串适用于简单的函数。多类函数值得更详细的文档字符串,涵盖所有参数、返回值、异常和特殊注释。

文档字符串应侧重于函数的作用(其接口),而不是其工作原理(实现)。它们成为函数 __doc__ 属性的一部分,并且可以通过 help() 访问。

类文档字符串

类文档字符串描述类的作用、属性和使用模式。它们出现在类定义之后、方法定义之前。此示例展示了全面的类文档。文档完善的类更容易使用和维护。

class_docstrings.py
class BankAccount:
    """A class representing a basic bank account.
    
    Attributes:
        account_number (str): Unique account identifier
        balance (float): Current account balance
        owner (str): Account holder's name
    """
    
    def __init__(self, account_number, owner, balance=0.0):
        """Initialize a new bank account.
        
        Args:
            account_number (str): Account identifier
            owner (str): Account holder name
            balance (float, optional): Initial balance. Defaults to 0.0.
        """
        self.account_number = account_number
        self.owner = owner
        self.balance = balance

# Additional example: Detailed class with methods
class Vector:
    """A mathematical vector in 2D space.
    
    Supports basic vector operations: addition, scalar multiplication,
    dot product, and magnitude calculation.
    
    Examples:
        >>> v1 = Vector(1, 2)
        >>> v2 = Vector(3, 4)
        >>> v1 + v2
        Vector(4, 6)
    """
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def magnitude(self):
        """Calculate the vector's magnitude.
        
        Returns:
            float: The vector's length
        """
        return (self.x**2 + self.y**2)**0.5

BankAccount 文档字符串描述了类的作用并列出了其属性。Vector 类展示了更详细的文档,包括使用示例。类文档字符串应提供足够的信息,以便用户在不阅读其实现的情况下使用该类。

类中的方法文档字符串遵循与函数文档字符串相同的原则。magnitude 方法演示了一个简单而清晰的文档字符串。总的来说,这些构成了全面的类文档。

模块文档字符串

模块文档字符串出现在 Python 文件的顶部,描述模块的作用、内容和用法。它们应该是任何导入或代码之前的三个引号字符串。此示例展示了一个正确记录的模块。模块文档字符串帮助用户理解文件在整个系统中的作用。

module_docstring.py
"""Financial calculations module.

Provides functions for common financial calculations including
interest, annuities, and investment returns.

Example:
    >>> from financial import calculate_interest
    >>> calculate_interest(1000, 0.05, 10)
    1628.894626777442

Copyright (c) 2025 Financial Tools Inc.
License: MIT
"""

import math
from datetime import date

# Additional example: Detailed module docstring
"""Image processing utilities.

This module contains functions for common image manipulation tasks:
- Color space conversions
- Filter applications
- Feature detection
- Image I/O operations

The implementation uses NumPy for efficient array operations and
supports both RGB and grayscale images.

Note:
    For advanced computer vision tasks, consider using OpenCV
    instead of these basic functions.
"""

financial 模块文档字符串描述了其作用、内容,并包含一个快速示例。版权和许可信息通常出现在模块文档字符串中。图像处理示例显示了更详细的文档,包括实现说明和建议。

模块文档字符串应足够全面,以便用户无需阅读所有代码即可了解模块提供的功能。它们成为模块的 __doc__ 属性,并被文档生成器使用。

文档字符串格式

Python 中存在几种文档字符串格式,每种都有其约定。最常见的是 Google 风格、NumPy/SciPy 风格和 reStructuredText。此示例比较了这些格式。一致的文档字符串风格提高了代码库的可读性。

formats.py
# Google Style
def google_style(a, b):
    """Compute the sum of two numbers.
    
    Args:
        a (int or float): First operand
        b (int or float): Second operand
    
    Returns:
        int or float: Sum of a and b
    
    Examples:
        >>> google_style(2, 3)
        5
    """
    return a + b

# NumPy/SciPy Style
def numpy_style(a, b):
    """Compute the sum of two numbers.
    
    Parameters
    ----------
    a : int or float
        First operand
    b : int or float
        Second operand
    
    Returns
    -------
    int or float
        Sum of a and b
    
    Examples
    --------
    >>> numpy_style(2, 3)
    5
    """
    return a + b

# reStructuredText Style
def rst_style(a, b):
    """Compute the sum of two numbers.
    
    :param a: First operand
    :type a: int or float
    :param b: Second operand
    :type b: int or float
    :return: Sum of a and b
    :rtype: int or float
    :example:
        >>> rst_style(2, 3)
        5
    """
    return a + b

Google 风格简洁易读,在通用 Python 代码中很受欢迎。NumPy 风格使用带有下划线的节标题,在科学 Python 中很常见。reStructuredText 更为冗长,但与 Sphinx 文档工具配合效果很好。这三种格式都是有效的——关键是在项目内保持一致。

每种格式都包含相同基本信息:参数、返回值和示例。根据项目的约定和文档工具进行选择。许多 IDE 可以以您喜欢的格式生成文档字符串存根。

文档生成

可以使用 Sphinx、pdoc 和 mkdocs 等工具将 Python 文档字符串自动转换为文档。此示例显示了为 Sphinx 格式化的文档字符串。正确格式化的文档字符串可以毫不费力地生成专业文档。

sphinx_docs.py
def sphinx_ready(a, b):
    """Compute the product of two numbers.
    
    This function multiplies two numbers with proper type checking.
    It serves as an example of Sphinx-compatible docstrings.
    
    :param a: First factor
    :type a: int or float
    :param b: Second factor
    :type b: int or float
    :return: Product of a and b
    :rtype: int or float
    :raises TypeError: If either argument isn't numeric
    
    .. note::
       This function doesn't handle complex numbers.
    
    .. warning::
       Floating-point multiplication may have precision issues.
    
    Example:
        .. code-block:: python
        
           result = sphinx_ready(3, 4)
           print(result)  # 12
    """
    if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
        raise TypeError("Numeric arguments required")
    return a * b

Sphinx 文档字符串使用 reStructuredText 语法,并带有 .. note::.. warning:: 等特殊指令。:param::type::return::raises: 标签创建结构化文档。代码示例使用 .. code-block:: 指令。

当由 Sphinx 处理时,这些文档字符串会生成格式精美的 HTML/PDF 文档,并带有适当的交叉引用。许多开源 Python 项目都采用这种方法来创建其官方文档。

最佳实践

为所有公共模块、函数、类和方法编写文档字符串。在代码更改时,请保持注释和文档字符串的最新状态。使用文档字符串记录接口(是什么),使用注释解释实现(如何)。遵循 PEP 8 和 PEP 257 风格指南。选择一种文档字符串格式,并在整个项目保持一致。

资料来源

从以下资源了解更多信息:PEP 257 文档字符串约定Google Python 风格指南Sphinx 文档

作者

我的名字是 Jan Bodnar,我是一名热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Python 教程