Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:argparse.Namespace对象的类型提示_Python_Python 3.x_Pycharm_Argparse_Type Hinting - Fatal编程技术网

Python:argparse.Namespace对象的类型提示

Python:argparse.Namespace对象的类型提示,python,python-3.x,pycharm,argparse,type-hinting,Python,Python 3.x,Pycharm,Argparse,Type Hinting,有没有办法让Python静态分析器(例如PyCharm中的其他IDE)在argparse.Namespace对象上获取类型提示?例如: parser = argparse.ArgumentParser() parser.add_argument('--somearg') parsed = parser.parse_args(['--somearg','someval']) # type: argparse.Namespace the_arg = parsed.somearg # <-

有没有办法让Python静态分析器(例如PyCharm中的其他IDE)在
argparse.Namespace
对象上获取类型提示?例如:

parser = argparse.ArgumentParser()
parser.add_argument('--somearg')
parsed = parser.parse_args(['--somearg','someval'])  # type: argparse.Namespace
the_arg = parsed.somearg  # <- Pycharm complains that parsed object has no attribute 'somearg'
虽然这是令人满意的,但我仍然不喜欢重复参数名称。如果参数列表大量增加,则更新这两个位置将非常繁琐。理想的做法是以某种方式从
解析器
对象中提取参数,如下所示:

parser = argparse.ArgumentParser()
parser.add_argument('--some-arg')
parser.add_argument('--another-arg')
MagicNamespace = parser.magically_extract_namespace()
parsed = parser.parse_args(['--some-arg', 'val1', '--another-arg', 'val2'])  # type: MagicNamespace
我在
argparse
模块中找不到任何可以实现这一点的东西,我仍然不确定是否有任何静态分析工具能够足够聪明地获取这些值,并且不会让IDE陷入瘫痪

还在搜索


更新2 根据hpaulj的评论,我能找到的最接近于上述方法的东西是从解析器的每个
\u操作中提取
dest
属性,该方法可以“神奇地”提取解析对象的属性:

parser = argparse.ArgumentParser()
parser.add_argument('--some-arg')
parser.add_argument('--another-arg')
MagicNamespace = namedtuple('MagicNamespace', [act.dest for act in parser._actions])
parsed = parser.parse_args(['--some-arg', 'val1', '--another-arg', 'val2'])  # type: MagicNamespace

但这仍然不会导致在静态分析中标记属性错误。如果我在
parser.parse_args
调用中传递
namespace=MagicNamespace
,这也是正确的。

考虑为
argparse.namespace
定义一个扩展类,该类提供您想要的类型提示:

class MyProgramArgs(argparse.Namespace):
    def __init__():
        self.somearg = 'defaultval' # type: str
然后使用
namespace=
将其传递给
parse_args

def process_argv():
    parser = argparse.ArgumentParser()
    parser.add_argument('--somearg')
    nsp = MyProgramArgs()
    parsed = parser.parse_args(['--somearg','someval'], namespace=nsp)  # type: MyProgramArgs
    the_arg = parsed.somearg  # <- Pycharm should not complain
def进程_argv():
parser=argparse.ArgumentParser()
parser.add_参数('--somearg')
nsp=MyProgramArgs()
parsed=parser.parse_args(['--somearg',someval'],namespace=nsp)#类型:MyProgramArgs

_arg=parsed.somearg#我不知道PyCharm是如何处理这些类型提示的,但是我理解
名称空间
代码

argparse.Namespace
是一个简单的类;本质上是一个对象,有一些方法可以使查看属性更容易。为了便于单元测试,它有一个
\uuuuu eq\uu
方法。您可以在
argparse.py
文件中读取定义

解析器
以最通用的方式与命名空间交互-使用
getattr
setattr
hasattr
。因此,您几乎可以使用任何
dest
字符串,甚至可以使用
.dest
语法无法访问的字符串

确保不要混淆
add\u参数
type=
参数;这是一个函数

按照另一个答案中的建议,使用自己的
名称空间
类(从头开始或子类化)可能是最好的选择。文档中对此进行了简要描述。虽然我已经多次建议使用它来处理特殊的存储需求,但我并没有看到它做了多少工作。所以你必须进行实验

如果使用子Parser,使用自定义命名空间类可能会中断

注意违约处理。大多数
argparse
操作的默认值为
None
。如果用户没有提供此选项,则在解析后使用此选项可以做一些特殊的事情

 if args.foo is None:
     # user did not use this optional
     args.foo = 'some post parsing default'
 else:
     # user provided value
     pass
这可能会妨碍输入提示。无论您尝试什么解决方案,请注意默认值


namedtuple
不能用作
名称空间

首先,正确使用自定义命名空间类是:

nm = MyClass(<default values>)
args = parser.parse_args(namespace=nm)
命名空间必须与
getattr
setattr
一起使用

namedtuple
的另一个问题是它没有设置任何类型的
类型
信息。它只定义字段/属性名称。所以静态类型没有什么可检查的

虽然可以很容易地从
解析器
中获取所需的属性名称,但无法获取任何所需的类型

对于简单的解析器:

In [82]: parser.print_usage()
usage: ipython3 [-h] [-foo FOO] bar
In [83]: [a.dest for a in parser._actions[1:]]
Out[83]: ['foo', 'bar']
In [84]: [a.type for a in parser._actions[1:]]
Out[84]: [None, None]
Actions
dest
是普通属性名称。但是
type
不是该属性的预期静态类型。它是一个可以转换或不转换输入字符串的函数。此处
None
表示输入字符串按原样保存

由于静态键入和
argparse
需要不同的信息,因此没有一种简单的方法从另一个生成一个

我认为最好的方法是创建自己的参数数据库,可能是在字典中,并使用自己的实用函数从中创建名称空间类和parsesr

假设
dd
是带有必要键的字典。然后我们可以创建一个参数:

parser.add_argument(dd['short'],dd['long'], dest=dd['dest'], type=dd['typefun'], default=dd['default'], help=dd['help'])
您或其他人必须从这样一个字典中提出一个名称空间类定义来设置
默认值(easy)和静态类型(hard?)。它包装
argparse
。您的示例实现为:

从点击导入点击
类参数分析器(Tap):
somearg:str
parsed=ArgumentParser().parse_args(['--somearg',someval'])
_arg=parsed.somearg
这是一张它正在运行的照片。

它位于PyPI上,可以通过以下方式安装:
pip安装类型参数解析器


完全公开:我是这个库的创建者之一。

谷歌快速搜索说,你可以在第一次使用局部变量时使用类型提示。在
parser=argparse.ArgumentParser()上试用它#键入:argparse.Namespace
,看看它是否有效。@Austin:
parser
在本例中是一个
argparse.ArgumentParser
对象,而不是
argparse.Namespace
对象。我想用args作为属性填充解析后的
对象。你说得对。我错过了
parsed
vs.
parser.
您真正想要的似乎是PyCharm在构建ArgumentParser时解析方法参数。我怀疑这是否有效。
add_参数
返回它刚刚创建的
操作
对象。看看它的属性<代码>解析器。_actions
是解析器在parsi期间使用的所有这些操作的列表
In [72]: MagicSpace=namedtuple('MagicSpace',['foo','bar'])
In [73]: nm = MagicSpace(1,2)
In [74]: nm
Out[74]: MagicSpace(foo=1, bar=2)
In [75]: nm.foo='one'
...
AttributeError: can't set attribute
In [76]: getattr(nm, 'foo')
Out[76]: 1
In [77]: setattr(nm, 'foo', 'one')    # not even with setattr
...
AttributeError: can't set attribute
In [82]: parser.print_usage()
usage: ipython3 [-h] [-foo FOO] bar
In [83]: [a.dest for a in parser._actions[1:]]
Out[83]: ['foo', 'bar']
In [84]: [a.type for a in parser._actions[1:]]
Out[84]: [None, None]
parser.add_argument(dd['short'],dd['long'], dest=dd['dest'], type=dd['typefun'], default=dd['default'], help=dd['help'])