python argparse store --foo=bar as args.key='foo', args.value='bar'
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(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_key
不会被定义,所以我必须使用 getattr()
.
操作覆盖虽然有效,但似乎不太正确。
我怀疑 argparse 背后的聪明才智已经以某种方式做到了这一点,我只是在文档和我的文档中遗漏了它
阅读 argparse.py.
什么是最好的,对,pythonic,做到这一点的方法?子解析器?
我正在使用 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')
操作 class 是 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
是一个包装另一个动作(由 subaction
指定的动作)的动作。添加参数时需要传递 container=
参数,以便它可以构造子操作。此外,还有一些关键字参数的摆弄,以便为子操作正确设置它们。
同样,这经过了非常有限的测试,因此它可能不适用于所有子操作,但它应该为您指明正确的方向。
子类化 Action
正是开发人员希望您做的。即使是默认的、最常见的操作 'store' 也是一个子类 argparse._StoreAction
。 argparse._StoreTrueAction
是 argparse._StoreConstAction
的子类,区别仅在于 default
和 const
默认值。
要处理缺少属性的情况,您可以通过几种方式初始化它们:
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
。
我想解析具有一组互斥选项的命令行。通常,我只使用 --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(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_key
不会被定义,所以我必须使用 getattr()
.
操作覆盖虽然有效,但似乎不太正确。
我怀疑 argparse 背后的聪明才智已经以某种方式做到了这一点,我只是在文档和我的文档中遗漏了它 阅读 argparse.py.
什么是最好的,对,pythonic,做到这一点的方法?子解析器? 我正在使用 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')
操作 class 是 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
是一个包装另一个动作(由 subaction
指定的动作)的动作。添加参数时需要传递 container=
参数,以便它可以构造子操作。此外,还有一些关键字参数的摆弄,以便为子操作正确设置它们。
同样,这经过了非常有限的测试,因此它可能不适用于所有子操作,但它应该为您指明正确的方向。
子类化 Action
正是开发人员希望您做的。即使是默认的、最常见的操作 'store' 也是一个子类 argparse._StoreAction
。 argparse._StoreTrueAction
是 argparse._StoreConstAction
的子类,区别仅在于 default
和 const
默认值。
要处理缺少属性的情况,您可以通过几种方式初始化它们:
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
。