修改后将* args,** kwargs传递给父类

时间:2016-03-01 21:09:23

标签: python

基于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中删除modedict,它仍然无效:

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)

如何让这个类接受参数,并且仍然正确地初始化了父类?

1 个答案:

答案 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)