python argparse store——foo=bar作为args.key=';foo';,参数值=';酒吧';

python argparse store——foo=bar作为args.key=';foo';,参数值=';酒吧';,python,argparse,Python,Argparse,我想分析一个命令行,它有一组互斥的选项。通常,我只使用--foobar,这将在名称空间中生成args.foo='bar' 然而,由于所有这些选项都是互斥的,我对选项名和传递给选项的参数都感兴趣,并且我有几个选项需要反馈到下游,所以我真正想要的是返回args.option\u name='foo',args.option\u value='bar'而不是args.foo='bar' 我所做的是: class KeyAction(argparse.Action): def __call__(

我想分析一个命令行,它有一组互斥的选项。通常,我只使用
--foobar
,这将在名称空间中生成
args.foo='bar'

然而,由于所有这些选项都是互斥的,我对选项名和传递给选项的参数都感兴趣,并且我有几个选项需要反馈到下游,所以我真正想要的是返回
args.option\u name='foo',args.option\u value='bar'
而不是
args.foo='bar'

我所做的是:

class KeyAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, values) 
        setattr(namespace, self.dest+'_key', option_string)

frob = parser.add_mutually_exclusive_group()
frob.add_argument('--foo', dest='thing', nargs='?', action=KeyAction)
frob.add_argument('--nar', dest='thing', nargs='?', action=KeyAction)
运行时,我的命名空间将如下所示:

Namespace(thing_key='--foo', thing='bar')
解析
--foo=bar
时。当然,遗憾的是,如果从未传入--foo或--nar,
namespace.thing\u key
没有定义,因此我必须使用
getattr()

动作覆盖虽然功能正常,但似乎并不正确

我怀疑argparse背后的聪明人已经不知何故把这件事做好了,我只是在文档和我的 读取argparse.py

做这件事最好的方法是什么?下级军官? 我正在使用python 3.5

所以我最终使用了你们两个答案中的数据来构造这个,它处理选项,它的参数,并在初始化时合理地设置一切

非常感谢您的提示、线索和验证。我很惊讶这在argparse中还没有出现,并成为标准化的东西。这是一种极端情况,但在使用互斥选项时,这不是一种极端情况

    class ValueAction(argparse.Action):
        """Override to store both the format type as well as the argument"""
        # pylint: disable=too-few-public-methods
        def __init__(self, option_strings, dest, **kwargs):
            self._dest = dest
            dest = dest + '_arguments'
            container = kwargs.pop('container')
            kwargs['action'] = kwargs.pop('subaction')
            action_class = container._pop_action_class(kwargs)
            if not callable(action_class):
                raise ValueError('unknown action "%s"' % (action_class,))
            self._action = action_class(option_strings, dest, **kwargs)
            super().__init__(option_strings, dest, **kwargs)

        def __call__(self, parser, namespace, values, option_string=None):
            self._action(parser, namespace, values, option_string)
            if isinstance(option_string, str):
                while option_string[0] in parser.prefix_chars:
                    option_string = option_string[1:]
            setattr(namespace, self._dest, option_string)

据我所知,您希望能够指定一个复合操作,以便保存在一个命名空间槽中使用的选项名,并执行其他操作的更新。例如,您希望能够写出以下内容:

group = argparse.mutually_exclusive_group()
group.add_argument('--foo', action=StoreOption, subaction='store_true')
group.add_argument('--bar', nargs='?', action=StoreOption, subaction='store')
action类是
StoreOption
,但它将调用
subaction
指定的操作来对名称空间对象执行其他更新

我得到的代码(测试非常有限)如下所示:

import argparse

class StoreOption(argparse.Action):
  def __init__(self, **kwargs):
    kwargs['action'] = kwargs.pop('subaction')
    container = kwargs.pop('container')

    action_class = container._pop_action_class(kwargs)
    if not callable(action_class):
      raise ValueError('unknown action "%s"' % (action_class,))

    kwargs['dest'] = 'thing'
    self._action = action_class(**kwargs)
    print "_action:", self._action

    super(StoreOption, self).__init__(
        option_strings= self._action.option_strings,
        dest= self._action.dest,
        nargs= self._action.nargs,
        const= self._action.const,
        default= self._action.default,
        type= self._action.type,
        choices= self._action.choices,
        required= self._action.required,
        help= self._action.help,
        metavar= self._action.metavar)

  def __call__(self, parser, namespace, values, option_string=None):
    print "got here:", option_string, namespace
    setattr(namespace, 'key', option_string)
    self._action(parser, namespace, values, option_string)
测试:

parser = argparse.ArgumentParser(prog='PROG')
group = parser.add_mutually_exclusive_group()
group.add_argument('--foo', container=group, action=StoreOption, subaction='store_true')
group.add_argument('--bar', container=group, nargs=2, action=StoreOption, subaction='store')

print parser.parse_args(['--bar', 'asd', 'qwe'])
-- prints: Namespace(key='--bar', thing=['asd', 'qwe'])
基本上,
StoreOption
是一个封装另一个操作的操作(由
子操作指定的操作)。添加参数时,需要传递
container=
参数,以便它可以构造子动作。此外,还需要对关键字参数进行一些修改,以便为子操作正确设置它们


同样,这已经经历了非常有限的测试,因此它可能不适用于所有子操作,但它应该为您指明正确的方向。

子类化
操作
正是开发人员希望您做的事情。即使是最常见的默认操作“store”也是一个子类,
argparse.\u StoreAction
argparse.\u StoreTrueAction
argparse.\u storeconstraction
的一个子类,只在
默认值
常量
默认值上有所不同

要处理缺少属性的情况,可以通过以下两种方式对其进行初始化:

set_defaults
允许您定义任何默认值,无论任何参数是否使用它们。在使用子Parser时用于将函数对象添加到命名空间的文档中

parser.set_defaults(thing_key=None, thing=None)
您还可以使用默认值创建名称空间,并将其作为
parse_args
的参数

myNamespace = argparse.Namespace(thing_key=None, thing=None)
parser.parse_args(names=myNamespace)
如果不希望命名空间中出现
foo=None
默认值,请将其默认值定义为
argparse.SUPPRESS