【问题标题】:Using type aliases in docstrings在文档字符串中使用类型别名
【发布时间】:2020-04-03 07:28:31
【问题描述】:

在文档字符串中使用类型别名或typing 对象是否有最佳实践?

这个问题可能会吸引基于意见的答案。但也可能是 特定解决方案有广泛接受的约定或外部工具支持。

Related question


示例:函数返回带有字符串键和值的字典。您会将什么类型放入“返回”部分下的文档字符串中? (我使用的是pandas style docstrings。)

选项 1:直接说它是一个字典。

import typing

strstrdict = typing.Dict[str, str]

def foo() -> strstrdict:
    '''
    bla bla

    Returns
    -------
    dict
        A dictionary with string keys and values that represents ...
    '''
    # code

选项 2:使用类型别名。

import typing

strstrdict = typing.Dict[str, str]

def foo() -> strstrdict:
    '''
    bla bla

    Returns
    -------
    strstrdict
        A dictionary with string keys and values that represents ...
    '''
    # code

选项 3:将"typing.Dict[str, str]" 放入文档字符串中。

import typing

strstrdict = typing.Dict[str, str]

def foo() -> strstrdict:
    '''
    bla bla

    Returns
    -------
    typing.Dict[str, str]
        A dictionary with string keys and values that represents ...
    '''
    # code

选项 4:还有别的吗?

编辑 1

“我正在使用 pandas 风格的文档字符串”您是在寻找这种风格的答案还是一般的答案?

我想最佳答案将尽可能涵盖一般情况和具体情况。我提到了pandas 样式,以明确为什么有“返回”部分而没有像“:param:”这样的说明。关于答案,我并没有死心塌地。

您是否真的在文档中包含别名,即用户能否发现别名 strstrdict 是什么?

目前没有关于别名的文档。用户可以查看themodule.strstrdict。我愿意在这里接受建议。

编辑 2

我链接到的样式指南碰巧提到了一个带有字符串键和值的字典。我正在寻找的答案也应该包括这样的情况:

from typing import Any, Callable, ContextManager, Iterable

ContextCallables = ContextManager[Iterable[Callable[[int, int], Any]]]

def foo() -> ContextCallabes:
    '''
    bla bla

    Returns
    -------
    ???
           some description
    '''
    # code

【问题讨论】:

  • "我正在使用 pandas 风格的文档字符串" 您是在寻找这种风格的答案还是一般来说?您是否真的在文档中包含别名,即用户可以发现别名 strstrdict 是什么?
  • @MisterMiyagi 问题只能询问特定的风格,否则将不得不以基于意见的方式关闭。
  • @a_guest pandas docstring guidenumpydoc docstring guide 对于通过 annotations/typing/aliases 提供的键入信息都不是权威的(根本不涉及该主题)。将问题限制在这些风格(我并不是说这不好)并不能阻止它基于意见(我并不是说它首先是)。
  • @MisterMiyagi 我编辑了我的问题以回应您的评论。
  • 我认为在文档字符串中包含输入/返回类型的做法早于 PEP 484 类型,可能需要重新考虑。现在,如果您使用类型提示,则完全忽略文档字符串中的类型实际上可能会更好:它与签名中已有的内容是多余的。同样,我希望任何现代文档工具都知道如何使用类型提示/以干净的方式公开它们。例如,sphinx 有几个插件(例如sphinx-autodoc-typehints)。当然,这只是我的看法。

标签: python typing docstring


【解决方案1】:

由于您明确提到了您所遵循的文档样式约定,因此基于意见的答案应该没有问题。

我们可以查看关于parameter types 的pandas 文档字符串指南部分:

对于复杂类型,定义子类型。对于dicttuple,由于存在不止一种类型,我们使用方括号来帮助读取类型(dict 是大括号,tuple 是普通括号)。

这意味着您应该按如下方式记录Dict[str, str]

Returns
-------
dict of {str : str}
    Some explanation here ...

您可以查看the docs 获取更多示例,包括其他类型。

【讨论】:

  • 这似乎对示例非常具体,恰好被样式短符号所涵盖。短符号未涵盖的类型呢?说ContextManager[Iterable[Callable[[int, int], Any]]]?
  • @MisterMiyagi 我认为样式指南对此仍然很清楚:“如果在 Python 模块中定义了类型,则必须指定模块。”。细节可以在参数文本中解释。因此,对于您的示例,这只是typing.ContextManager。现在,如果我们将其放入字典中并制作类似Dict[str, ContextManager[...]] 的内容会怎样?样式指南提到:“对于复杂类型,定义子类型。”它没有说“......并为每种类型递归地执行此操作。”所以它只需要一级细节:dict of {str : typing.ContextManager}。更多详情可以去正文。
  • 我不明白风格指南是如何明确这一点的。该指南仅涉及具体类型,具有针对文字容器的特殊规则以及两个抽象的类数组和可迭代的规则。没有抽象泛型类型或其别名的概念,如键入所表达的那样。
  • @MisterMiyagi 该指南包括以下部分:“如果类型是在 Python 模块中定义的,[...]”。因此,对于要包含在类型定义中的任何类型,您都可以检查此条件是否满足。如果你将你的函数注释为ContextManager[...],那么由于ContextManager是在一个模块中定义的(typing),它应该被定义为typing.ContextManager。另一方面,如果您使用了别名my_alias = ContextManager[...],那么它没有在(另一个)模块中定义,因此您可以只使用my_alias。使用 Sphinx `:data:`my_alias``` 可用于链接。
  • 这是在回避问题。问题不在于ContextManager[Iterable[Callable[[int, int], Any]]] 是否应该与模块前缀一起使用。问题是它是否应该以完全丑陋的形式逐字使用(选项 3),缩短为无意义的 ContextManager(选项 1),还是使用有意义但非通用的 ContextualCallables(选项 2)。对于具体类型,这是样式指南在一般情况下所讨论的所有内容,所有选项都是相同的。对于具有抽象、泛型和别名类型的typing,情况并非如此。
猜你喜欢
  • 2019-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-14
  • 1970-01-01
相关资源
最近更新 更多