Python:argparse.Namespace对象的类型提示
有没有办法让Python静态分析器(例如PyCharm中的其他IDE)在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 # <-
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]
Actionsdest
是普通属性名称。但是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'])