python argparse store --foo=bar as args.key='foo', args.value='bar' [英] python argparse store --foo=bar as args.key='foo', args.value='bar'

查看:27
本文介绍了python argparse store --foo=bar as args.key='foo', args.value='bar'的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想解析具有互斥选项组的命令行.通常,我只使用 --foo bar 这会在命名空间中产生 args.foo = 'bar'

但是,由于所有这些选项都是互斥的,我对选项名称和传递给选项的参数都很感兴趣,而且我有几个需要向下游提供的选项,我会真正喜欢的是在我的命名空间中取回 args.option_name = 'foo', args.option_value = 'bar' 而不是 args.foo='bar'.>

我所做的是:

class KeyAction(argparse.Action):def __call__(self, parser, namespace, values, option_string=None):setattr(命名空间,self.dest,值)setattr(命名空间,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)

运行时,我的命名空间将如下所示:

命名空间(thing_key='--foo', thing='bar')

--foo=bar 被解析时.当然,遗憾的是,如果从不传入 --foo 或 --nar,namespace.thing_key 不会被定义,所以我必须使用 getattr().

动作覆盖虽然有效,但似乎不太正确.

我怀疑 argparse 背后的聪明才智已经以某种方式做到了这一点,而我只是在文档和我的文档中遗漏了它读取 argparse.py.

什么是最好的、正确的、pythonic 的方法来做到这一点?子解析器?我使用的是 python 3.5.

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

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

 class ValueAction(argparse.Action):"""覆盖以存储格式类型和参数"""# pylint: disable=too-few-public-methodsdef __init__(self, option_strings, dest, **kwargs):self._dest = destdest = dest + '_arguments'容器 = kwargs.pop('容器')kwargs['action'] = kwargs.pop('subaction')action_class = container._pop_action_class(kwargs)如果不可调用(action_class):引发 ValueError('未知动作 "%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(解析器,命名空间,值,option_string)如果 isinstance(option_string, str):而 parser.prefix_chars 中的 option_string[0]:option_string = option_string[1:]setattr(命名空间,self._dest,option_string)

解决方案

子类化 Action 正是开发人员希望你做的.即使是默认的、最常见的操作,store"也是一个子类,argparse._StoreAction.argparse._StoreTrueActionargparse._StoreConstAction 的子类,区别仅在于 defaultconst 默认值.>

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

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

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.

I'd like to parse a command line that has a mutually exclusive group of options. Normally, I'd just use --foo bar which would produce, in the namespace, args.foo = 'bar'

However, since all of these options are mutually exclusive, and I'm interested in both the option name and the argument passed to the option, and I have several of these options that need to be fed downstream, what I'd really like is to get back args.option_name = 'foo', args.option_value = 'bar' in my namespace instead of args.foo='bar'.

What I've done is:

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)

when run, my namespace will look like:

Namespace(thing_key='--foo', thing='bar')

when --foo=bar is parsed. Of course, sadly, if --foo or --nar is never passed in, namespace.thing_key doesn't get defined, so I have to use a getattr().

The action override, while functional, doesn't seem really right.

I suspect the brilliant minds behind argparse already got this right somehow, and I'm just missing it in the documentation and from my read of argparse.py.

What's the best, right, pythonic, way to do this? Subparsers? I'm using python 3.5.

So I ended up using data from both of your answers to construct this, which handles the option, it's argument, and sets everything sanely at initialization time.

Thank you very much for the hints, clues, and validation. I'm surprised this hasn't come up in argparse before and become something standardized. It is a corner case, but isn't that much of a corner case when using mutually exclusive options.

    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)

解决方案

Subclassing Action is exactly what the developers expect you to do. Even the default, most common action, 'store' is a subclass, argparse._StoreAction. argparse._StoreTrueAction is a subclass of argparse._StoreConstAction, differing only in the default and const defaults.

To deal with the missing attribute case you could initialize them in a couple of ways:

set_defaults lets you define any defaults, regardless of whether any arguments use them or not. In the documentation that is used to add function objects to the namespace when using subparsers.

parser.set_defaults(thing_key=None, thing=None)

You could also create a namespace with the defaults, and pass that as an argument to parse_args.

myNamespace = argparse.Namespace(thing_key=None, thing=None)
parser.parse_args(names=myNamespace)

If you don't want a foo=None default in the namespace, define its default as argparse.SUPPRESS.

这篇关于python argparse store --foo=bar as args.key='foo', args.value='bar'的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆