如何记录复杂 API 函数的小改动?

act*_*nda 8 python documentation

假设我们有一个复杂的 API 函数,它是从某个库中导入的。

def complex_api_function(
        number, <lots of positional arguments>,
        <lots of keyword arguments>):
    '''really long docstring'''
    # lots of code
Run Code Online (Sandbox Code Playgroud)

我想围绕该函数编写一个简单的包装器以进行微小的更改。例如,应该可以将第一个参数作为字符串传递。如何记录这个?我考虑了以下选项:

选项1:

def my_complex_api_function(number_or_str, *args, **kwargs):
    '''
    Do something complex.

    Like `complex_api_function`, but first argument can be a string.

    Parameters
    ----------
    number_or_str : int or float or str
        Can be a number or a string that can be interpreted as a float.
        <copy paste description from complex_api_function docstring>
    *args
        Positional arguments passed to `complex_api_function`.
    **kwargs
        Keyword arguments passed to `complex_api_function`.

    Returns
    -------
    <copy paste from complex_api_function docstring>

    Examples
    --------
    <example where first argument is a string, e.g. '-5.0'>

    '''
    return complex_api_function(float(number_or_str), *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

缺点:用户必须查看 的文档complex_api_function才能获取有关*args和 的信息**kwargs。当复制粘贴的部分complex_api_function发生变化时需要调整。

选项 2:

复制并粘贴complex_api_function的签名(而不是使用*argsand **kwargs)及其文档字符串。对提到第一个参数也可以是字符串的文档字符串进行微小更改。添加示例。

缺点:冗长,更改时必须complex_api_function更改。

选项 3:

装饰my_complex_api_functionfunctools.wraps(complex_api_function)

缺点:没有信息number也可以是字符串。


我正在寻找一个不取决于my_complex_api_function. 该程序应该适用于对原始文件的任何微小调整complex_api_function

Rap*_*aer 5

您可以使用附录自动执行原始文档字符串的“专业化” 。例如,pydoc正在使用特殊属性__doc__。您可以编写一个装饰器,__doc__用您的附录自动覆盖原始函数。

例如:

def extend_docstring(original, addendum):
    def callable(func):
        func.__doc__ = original + addendum
        return func

    return callable


def complex_api_function(a, b, c):
    '''
    This is a very complex function.

    Parameters
    ----------
    a: int or float
        This is the argument A.
    b: ....
    '''
    print('do something')

@extend_docstring(
    complex_api_function.__doc__,
    '''
    Addendum
    --------
    Parameter a can also be a string
    '''
)
def my_complex_api_function(a, b, c):
    return complex_api_function(float(a), b, c)
Run Code Online (Sandbox Code Playgroud)

或者...

def extend_docstring(original):
    def callable(func):
        func.__doc__ = original + func.__doc__
        return func

    return callable


def complex_api_function(a, b, c):
    '''
    This is a very complex function.

    Parameters
    ----------
    a: int or float
        This is the argument A.
    b: ....
    '''
    print('do something')

@extend_docstring(complex_api_function.__doc__)
def my_complex_api_function(a, b, c):
    '''
    Addendum
    --------
    Parameter a can also be a string
    '''
    return complex_api_function(float(a), b, c)
Run Code Online (Sandbox Code Playgroud)

如果你运行pydoc ( pydoc3 -w my_module.py) 它会产生:pydoc 生成的 html 的预览

附加说明:如果您使用的是 Python 3,则可以使用注释来记录函数参数的类型。它提供了很多好处,而不仅仅是文档。例如:

from typing import Union

def my_complex_api_function(number_or_str: Union[int, float, str], *args, **kwargs):
Run Code Online (Sandbox Code Playgroud)


Leg*_*ooj 3

我会推荐如下内容:

def my_complex_api_function(number_or_str, *args, **kwargs):
    """This function is a light wrapper to `complex_api_function`.
    It allows you to pass a string or a number, whereas `complex_api_function` requires a 
    number. See :ref:`complex_api_function` for more details.

    :param number_or_str: number or str to convert to a number and pass to `complex_api_function`.
    :param args: Arguments to pass to `complex_api_function`
    :param kwargs: Keyword arguments to pass to `complex_api_function`
    :return: Output of `complex_api_function`, called with passed parameters
    """
Run Code Online (Sandbox Code Playgroud)

这是清晰和简洁的。但也请记住,如果使用像 sphinx 这样的文档系统,请使用:ref:`bob`或类似的链接功能。

  • 我什至不会提及“complex_api_function”对其参数期望什么类型,因为这只是重复信息(也许它们也有多个选项)。想必包装器的用户已经熟悉原始函数,如果不熟悉,您可以随时将他们指向原始文档。无论如何,我认为这是要走的路,只记录原始函数中添加的内容+提供有关新类型如何转换为原始类型的详细信息(这些详细信息可能很重要)。即如何处理该参数以便与原始函数兼容。 (2认同)