Python:类型提示中的私有类型?

Python: Private Types in Type Hints?

我喜欢类型提示,尤其是我的方法参数。在我当前的脚本中,一个函数应该检索 argparse._SubParsersAction 类型的参数。从下划线可以看出,这是约定俗成的私有类型。我想这就是为什么 PyCharm 在尝试导入它时抱怨错误消息 Cannot find reference '_SubParsersAction' in 'argparse.pyi'(尽管它在那里)。

脚本运行但是感觉不对。错误消息对我来说似乎是合理的,因为私有类型应该是……好吧,私有的。 因此,我的第一个问题是为什么 public 方法 ArgumentParser.add_subparsers() returns 首先是一个私有类型的对象。

我一直在寻找 public 超级 class 或接口,_SubParsersAction 确实是从 argparse.Action 扩展而来的,但这对我没有帮助,因为 Action 没有定义 _SubParsersActionadd_parser() 方法(我需要)。

所以我的下一个问题是:我可以将类型提示与 argparse API 一起使用吗?或者它只是部分可能,因为 API 是在引入类型提示之前很久就设计的?还是我的打字想法不适合 Python 的类型系统?

这是我受影响的代码片段。它创建了一个带有子参数的参数解析器,如文档 (https://docs.python.org/dev/library/argparse.html#sub-commands) 中所述。

main.py

from argparse import ArgumentParser

import sub_command_foo
import sub_command_bar
import sub_command_baz


def main():
    parser = ArgumentParser()
    sub_parsers = parser.add_subparsers()

    sub_command_foo.add_sub_parser(sub_parsers)
    sub_command_bar.add_sub_parser(sub_parsers)
    sub_command_baz.add_sub_parser(sub_parsers)

    args = parser.parse_args()
    args.func(args)


if __name__ == '__main__':
    main()

sub_command_foo.py

from argparse import _SubParsersAction, Namespace


def add_sub_parser(sub_parsers: _SubParsersAction):
    arg_parser = sub_parsers.add_parser('foo')
    
    # Add arguments...

    arg_parser.set_defaults(func=run)


def run(args: Namespace):
    print('foo...')

问题出在sub_command_foo.py。 PyCharm 在第一行显示错误消息 Cannot find reference '_SubParsersAction' in 'argparse.pyi' from argparse import _SubParsersAction, Namespace

我不使用 pycharm,也没有对类型提示做太多工作,所以无法帮助您。但我很了解argparse。该模块的大部分内容是在 2010 年之前编写的,从那时起就以蜗牛的速度对其进行了修改。它在 OOP 意义上组织得很好,但文档更像是美化的教程,而不是正式的参考。也就是说,它着重于用户将需要的功能和方法,而不是试图正式记录所有 classes 和方法。

我在交互式 ipython 会话中进行了大量测试,我可以在其中查看命令返回的对象。

在Python中,public和私有classes和方法之间的区别并不像其他语言那样正式。 '_' 前缀确实标记了 'private' 东西。它们通常没有记录,但仍然可以访问。有时 '*' 导入会导入所有不以它开头的对象,但是 argparse 有一个更明确的 __all__ 列表。

argparser.ArgumentParser 确实创建了一个对象实例。但是 class 继承自 2 'private' classes。 add_argument 方法创建一个 Action 对象,并将其放在 parser._actions 列表中。它还 returns 它给用户(尽管通常忽略该引用)。动作其实就是一个subclass(都是'private')。 add_subparsers 只是这个 add_argument 的一个特殊版本。

add_parser 方法创建了一个 ArgumentParser 对象

我觉得需要单独导入 'private' classes 的类型提示会适得其反。您不应该明确引用那些 classes,即使您的代码生成了它们。有些人(公司)担心他们会在没有通知的情况下被更改,从而破坏他们的代码。知道 argparse 的变化有多慢,我不会太在意它。