如何为函数参数的字典键添加文档说明?

3

我正在尝试找出如何在不使用Dict[str, str]的情况下为传递给函数的字典参数提供类型提示,因为它不能提供键是什么。

到目前为止,我已经尝试了两种方法,一种是使用typing_extensions,以便与3.6兼容,另一种是使用pydantic,但我无法显示提示。

考虑以下示例代码:

from typing_extensions import TypedDict
from pydantic import BaseModel

class Some(TypedDict):
    """keya is some key"""
    keya: str
    """another_key is another key"""
    another_key: str

def some(a: Some) -> None:
    print(a.get('keya'))
    return None


some({'keya': 'key', 'another_key': 'nonething'})

enter image description here

如预期的那样,some函数的类型提示显示了类型Some,但没有显示其键。

我的目标是两件事:

  • 在函数参数为字典时提供键提示(最重要的)
  • 使用Sphinx生成文档,以便在文档中反映键。

编辑

正如其中一条评论所指出的那样,我可以通过使用**kwargs在一定程度上达到这个目的,但这不是我的意图。设置**kwargs也不会给我类型提示。


这似乎是在寻求解决一个完全自我引起的问题。如果您真的希望在单个字典参数中使用多个特定参数,为什么要这样做呢?您是否考虑过不将参数作为字典传递,而是作为单独的关键字参数传递?如果调用者已经将参数打包到字典中,则可以使用 some(**some_dict) - Blckknght
@Blckknght 是的,你是对的。我可以轻松地用 **kwargs 绕过这个问题,但这不是本意。问题更多地是围绕着是否能够做到这一点,如果不能,我也理解。 - securisec
@Blckknght 只是要澄清一下,**kwargs不能将有效键的类型提示显示给用户,我的示例在此帖子中进行了简化。如果函数需要10个参数,其中包含字典、列表和字符串混合,那么我无法完成我想要完成的工作。 - securisec
1
建议不要使用 **kwargs,而是直接将 keya, another_key 作为函数的参数。然后可以通过 some(**d) 将包含这些键的字典传递给函数。 - Mad Physicist
您可以使用默认值和 **kwargs 分别处理输入中缺失或额外的键。 - Mad Physicist
2个回答

1
我认为在这种情况下,更好的做法是向你的编辑器提出功能请求/提交拉取请求,以改进其类型提示质量。同样地,对于sphinx,您可以提交一个拉取请求,确保文档要么正确链接到Some的定义,要么在函数签名本身中包含更详细的描述。
毕竟,你面临的问题是你的编辑器/sphinx的限制,而不是Python或类型提示的问题,如果你从源头解决问题,你可能会获得更好的长期效果。
如果使用Some的“构造函数”而不是传递字典文字,您也可能会获得更好的结果。至少对我来说,在PyCharm中这样做可以让我获得完整的键提示。不确定你的编辑器是否也是如此。
some(Some(keya='key', another_key='nonething'))

请注意,执行Some(...)实际上只会在运行时返回一个普通的字典,因此这不应导致任何行为上的差异。
尝试执行以下操作也可能值得一试:
x: Some = {
    "keya": "key",
    "another_key": "nonething",
}
some(x)

…以查看您的编辑器是否可以使用该表单提供更好的提示。


0

我已经通过以下代码缩小了可能的解决方案范围。它满足大部分要求:

  • mypy类型检查通过
  • 显示键
  • 文档也显示键和类型
  • 这种解决方案的主要限制是,由于默认值,mypy认为该值是可选的,因此解决方案还不完整。

使用validate_items函数,我可以验证值是否存在。请参阅代码片段上的注释并提出建议。

from typing_extensions import TypedDict
from typing import Union

class Some(TypedDict):
    keya: str
    another_key: str

def validate_items(v: dict) -> None:
    for key, value in v.items():
        assert isinstance(value,str), '{} is required'.format(key)
        # Would love to pull the type of a key from the Some class here or
        # would love to put the validation in the Some class itself


def some(a: Some={'keya': '', 'another_key': ''}) -> None:
    """[summary]

    Args:
        a (Some, optional): [description]. Defaults to {'keya': '', 'another_key': ''}.

    Returns:
        [type]: [description]
    """    
    validate_items(dict(a))
    print(a.get('keya'))
    return None

enter image description here

在这个屏幕截图中,我可以看到mypy正在抱怨预期的 None 值,并且在弹出式帮助中,我们还可以看到需要在字典中传递的键和被设置为它的类型。
这个解决方案感觉有点hacky,如果有任何更pythonic的修正,我们将不胜感激。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接