基于previous post,我实现了以下修改后的argparse.Action
,它会生成键值对。
我希望允许动态设置nargs
,并提供在密钥可能出现多次的情况下使用defaultdict(list)
的选项。
以下是我的实施:
import argparse
from collections import defaultdict
class NamespaceAction(argparse.Action):
"""
This modified action allows me to group together key-value pairs passed to an argument.
Extended to produce a defaultdict(list) if requested, so that a key can appear more than once.
"""
def __init__(self, *args, **kwargs):
self.nargs = kwargs.get('nargs', 1)
self.mode = kwargs.get('mode', 'dict') # default mode is dict
super(NamespaceAction, self).__init__(*args, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
# The default value is often set to None rather than an empty list.
current_arg_vals = getattr(namespace, self.dest, []) or []
setattr(namespace, self.dest, current_arg_vals)
arg_vals = getattr(namespace, self.dest)
try:
if self.mode == 'dict':
arg_vals.append(argparse.Namespace(**dict(v.split('=') for v in values)))
elif self.mode == 'defaultdict':
d = defaultdict(list)
for v in values:
v = v.split('=')
d[v[0]].append(v[1])
arg_vals.append(argparse.Namespace(**d))
else:
raise NotImplementedError("only dict or defaultdict")
except TypeError:
raise RuntimeError('Group {} appears to be incorrectly formatted'.format(values))
但是,使用此选项会导致TypeError: __init__() got an unexpected keyword argument 'mode'
。但是,如果我从args / kwargs中删除mode
和dict
,它仍然无效:
def __init__(self, *args, **kwargs):
self.nargs = kwargs.get('nargs', 1)
self.mode = kwargs.get('mode', 'dict') # default mode is dict
if 'mode' in kwargs:
del kwargs['mode']
if 'nargs' in kwargs:
del kwargs['nargs']
super(NamespaceAction, self).__init__(*args, **kwargs)
导致TypeError: __init__() takes at least 3 arguments (1 given)
。
如何让这个类接受参数,并且仍然正确地初始化了父类?
答案 0 :(得分:2)
你期望nargs
是位置的,但它是argparse.Action
的可选参数;根据文件:
Action类必须接受两个位置参数以及传递给
ArgumentParser.add_argument()
的任何关键字参数,但action
本身除外。
您可以尝试:
def __init__(self, *args, **kwargs):
# To force nargs, look it up, but don't bother setting on self;
# just let it pass to the parent, if you remove it from kwargs, the
# parent __init__ overwrites self.nargs with None
nargs = kwargs['nargs']
assert isinstance(nargs, int) or nargs == "+"
# dict.pop is like get, but removes the mapping if it exists
self.mode = kwargs.pop('mode', 'dict') # Will use 'dict' as default
# Pass along remaining arguments
super(NamespaceAction, self).__init__(*args, **kwargs)