我想使用argparse
收集一些选项作为词典。我已经编写了一个自定义Action类,如下所示。问题是永远不会调用__call__
方法。
#!/usr/bin/env python3
import argparse
class UpdateDict(argparse.Action):
def __init__(self, option_strings, dest, nargs=None, **kwargs):
print('UpdateDict', option_strings, dest, nargs)
if nargs != 1:
raise ValueError("nargs must be 1")
super(UpdateDict, self).__init__(option_strings, dest, nargs=nargs, **kwargs)
print(self)
def __call__(self, parser, namespace, values, option_string=None):
print('%r %r %r' % (namespace, values, option_string))
dest = getattr(namespace, self.dest)
print(dest)
key = option_string[1]
dest.update(key = values[0])
def parse_args():
parser = argparse.ArgumentParser(description='formula alpha')
parser.add_argument('formula', nargs=1, type=str, help='alpha formula')
parser.set_defaults(mydict={})
parser.add_argument('-a', '--alpha', nargs=1, type=str, default=['alas'], action=UpdateDict, dest='mydict')
parser.add_argument('-b', '--beta', nargs=1, type=int, default=[0], action=UpdateDict, dest='mydict')
if __name__ == '__main__':
args = parse_args()
print(args)
答案 0 :(得分:0)
您的parse_args
函数需要返回它创建的解析器,因为您需要parse_args
方法进行实际解析。此外,您应该从sys.argv[1:]
获取参数,基本上是除主程序参数(即您的脚本名称)之外的参数。因此,您应该将parse_args
重命名为更合适的名称。一个不完整的例子:
def make_parser():
# your ArgumentParser construction code ...
return parser
if __name__ == '__main__':
import sys
parser = make_parser()
parser.parse_args(sys.argv[1:])
请注意,您在执行操作时遇到一些小问题,需要修复。当我将所有代码(添加了return parser
)放在您的代码构建的ArgumentParser
上时,就会出现问题:
>>> parser.parse_known_args(['-b', '1'])
Namespace(formula=None, mydict=['alas']) [1] '-b'
['alas']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.4/argparse.py", line 1769, in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
File "/usr/lib/python3.4/argparse.py", line 1975, in _parse_known_args
start_index = consume_optional(start_index)
File "/usr/lib/python3.4/argparse.py", line 1915, in consume_optional
take_action(action, args, option_string)
File "/usr/lib/python3.4/argparse.py", line 1843, in take_action
action(self, namespace, argument_values, option_string)
File "<stdin>", line 13, in __call__
AttributeError: 'list' object has no attribute 'update'
答案 1 :(得分:0)
使用您的脚本,简化为专注于将值放在mydict
:
import argparse
class UpdateDict(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
adict = getattr(namespace, 'mydict')
adict.update({self.dest: values})
def parse_args():
parser = argparse.ArgumentParser()
parser.set_defaults(mydict={})
parser.add_argument('-a', '--alpha', default='alas', action=UpdateDict)
parser.add_argument('-b', '--beta', type=int, default=0, action=UpdateDict)
return parser.parse_args() # parse and return
if __name__ == '__main__':
args = parse_args()
print(args)
我得到了
2333:~/mypy$ python3 stack39263156.py
Namespace(alpha='alas', beta=0, mydict={})
2337:~/mypy$ python3 stack39263156.py -a one
Namespace(alpha='alas', beta=0, mydict={'alpha': 'one'})
2337:~/mypy$ python3 stack39263156.py -a one -b 2
Namespace(alpha='alas', beta=0, mydict={'beta': 2, 'alpha': 'one'})
如果需要,您可以恢复nargs=1
测试,但默认None
意味着1个参数。大多数人都不使用nargs=1
。它确保值是单个元素列表;大多数人都想要多个元素列表(例如&#39; +&#39;或&#39; *&#39; nargs)。
我喜欢您使用set_defaults
将mydict
放入命名空间。然后我从命名空间中检索它,并使用参数dest
作为key
来更新它。您的版本会混淆dest
,并覆盖mydict
属性。
默认store_action
使用setattr(namespace, self.dest, values)
来执行相同的操作,但使用命名空间对象而不是嵌入式mydict
。
通常的默认处理会填充alpha
和beta
属性(dest
)。要将这些内容放在mydict
中,您必须使用类似
parser.set_defaults(mydict={'alpha':'alas', 'beta':0})
SUPPRESS
可用于将默认值保留在通常的dest
属性
parser.add_argument('-a', '--alpha', action=UpdateDict, default=argparse.SUPPRESS)
parser.add_argument('-b', '--beta', type=int, action=UpdateDict)
无争论运行会产生:
2347:~/mypy$ python3 stack39263156.py
Namespace(beta=None, mydict={'beta': 0, 'alpha': 'alas'})
使用嵌入式字典是一个有趣的想法,虽然我不确定它添加了什么。建议将vars(args)
作为将namespace
转换为字典的方法。
{'mydict': {'alpha': 'one', 'beta': 2}, 'beta': None}