argparse:将参数与另一个参数相关联
argparse: Associate arguments with another argument
使用 argparse,可以重复一个参数并将所有值收集到一个列表中:
parser = ArgumentParser()
parser.add_argument('-o', '--output', action='append')
args = parser.parse_args(['-o', 'output1', '-o', 'output2'])
print(vars(args))
# {'output': ['output1', 'output2']}
我正在寻找一种将标志与这些参数中的每一个相关联的方法,以便可以这样做:
args = parser.parse_args(['-o', 'output1', '--format', 'text',
'-o', 'output2', '--format', 'csv'])
并得到这样的输出(或类似的东西):
{'output': {'output1': {'format': 'text'},
'output2': {'format': 'csv'}
}
}
理想情况下,这些标志应遵循通常的语义 - 例如,--format
可以是可选的,或者可以有多个参数与每个 -o
输出相关联,在这种情况下它们应该是可以通过的以任何顺序(即 -o output1 -a -b -c
应等同于 -o output1 -c -a -b
)。
这可以用 argparse 完成吗?
只需定义 -o
接受两个参数。
parser.add_argument('-o', '--output', nargs=2, action='append')
然后-o output1 text -o output2 csv
会产生类似
的东西
args = p.parse_args(['-o', 'output1', 'text', '-o', 'output2', 'csv'])
assert args.output == [['output1', 'text'], ['output2', 'csv']]
您可以 post-process args.output
以获得所需的 dict
,或者定义自定义 Action
,其 __call__
方法将构建 dict
值本身。
3 个解析器在一组通用的 -o
和 -f
标志上运行:
简单追加 - 2 dest
:
之间没有联系
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output', action='append')
parser.add_argument('-f', '--format', action='append')
args = parser.parse_args(['-o', 'output1', '-o', 'output2'])
print(args)
args = parser.parse_args(['-o', 'output1', '--format', 'text',
'-o', 'output2', '--format', 'csv'])
print(args)
args = parser.parse_args(['-o', 'output1',
'-o', 'output2', '--format', 'csv',
'-o', 'output3', '-f1', '-f2'])
print(args)
print()
nargs='+'
;将参数放在一起,但不使用 format
标志:
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output', action='append', nargs='+')
#parser.add_argument('-f', '--format', action='append')
args = parser.parse_args(['-o', 'output1', '-o', 'output2'])
print(args)
args = parser.parse_args(['-o', 'output1', 'text',
'-o', 'output2', 'csv'])
print(args)
args = parser.parse_args(['-o', 'output1',
'-o', 'output2', 'csv',
'-o', 'output3', '1', '2'])
print(args)
print()
自定义 classes 来自 append
class。为每个 output
创建一个字典。 format
修改最后一个 output
字典:
class Foo1(argparse._AppendAction):
def __call__(self, parser, namespace, values, option_string=None):
items = argparse._copy.copy(argparse._ensure_value(namespace, self.dest, []))
dd = {'output': values, 'format': []}
items.append(dd)
setattr(namespace, self.dest, items)
class Foo2(argparse._AppendAction):
def __call__(self, parser, namespace, values, option_string=None):
items = argparse._copy.copy(argparse._ensure_value(namespace, self.dest, []))
last = items[-1] # error if -f before -o
last['format'].append(values)
setattr(namespace, self.dest, items)
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output', action=Foo1)
parser.add_argument('-f', '--format', action=Foo2, dest='output')
args = parser.parse_args(['-o', 'output1', '-o', 'output2'])
print(args)
args = parser.parse_args(['-o', 'output1', '--format', 'text',
'-o', 'output2', '--format', 'csv'])
print(args)
args = parser.parse_args(['-o', 'output1',
'-o', 'output2', '--format', 'csv',
'-o', 'output3', '-f1', '-f2'])
print(args)
print()
产生:
1238:~/mypy$ python stack48504770.py
Namespace(format=None, output=['output1', 'output2'])
Namespace(format=['text', 'csv'], output=['output1', 'output2'])
Namespace(format=['csv', '1', '2'], output=['output1', 'output2', 'output3'])
Namespace(output=[['output1'], ['output2']])
Namespace(output=[['output1', 'text'], ['output2', 'csv']])
Namespace(output=[['output1'], ['output2', 'csv'], ['output3', '1', '2']])
Namespace(output=[{'output': 'output1', 'format': []},
{'output': 'output2', 'format': []}])
Namespace(output=[{'output': 'output1', 'format': ['text']},
{'output': 'output2', 'format': ['csv']}])
Namespace(output=[{'output': 'output1', 'format': []},
{'output': 'output2', 'format': ['csv']},
{'output': 'output3', 'format': ['1', '2']}])
()
基于 中的代码,我对实现进行了调整,使其更加通用。它由 2 个自定义 Action 类、ParentAction
和 ChildAction
.
组成
用法
parser = argparse.ArgumentParser()
# first, create a parent action:
parent = parser.add_argument('-o', '--output', action=ParentAction)
# child actions require a `parent` argument:
parser.add_argument('-f', '--format', action=ChildAction, parent=parent)
# child actions can be customized like all other Actions. For example,
# we can set a default value or customize its behavior - the `sub_action`
# parameter takes the place of the usual `action` parameter:
parser.add_argument('-l', '--list', action=ChildAction, parent=parent,
sub_action='append', default=[])
args = parser.parse_args(['-o', 'output1', '-l1', '-l2',
'-o', 'output2', '--format', 'csv',
'-o', 'output3', '-f1', '-f2'])
print(args)
# output (formatted):
# Namespace(
# output=OrderedDict([('output1', Namespace(list=['1', '2'])),
# ('output2', Namespace(format='csv', list=[])),
# ('output3', Namespace(format='2', list=[]))
# ])
# )
注意事项
- 子动作必须始终在父动作之后。
例如,
--format csv -o output1
将不起作用并显示一条错误消息。
不能用相同的名称注册多个 ChildActions,即使父级不同也是如此。
示例:
parent1 = parser.add_argument('-o', '--output', action=ParentAction)
parser.add_argument('-f', action=ChildAction, parent=parent1)
parent2 = parser.add_argument('-i', '--input', action=ParentAction)
parser.add_argument('-f', action=ChildAction, parent=parent2)
# throws exception:
# argparse.ArgumentError: argument -f: conflicting option string: -f
代码
import argparse
from collections import OrderedDict
class ParentAction(argparse.Action):
def __init__(self, *args, **kwargs):
super().__init__(*args, default=OrderedDict(), **kwargs)
self.children = []
def __call__(self, parser, namespace, values, option_string=None):
items = getattr(namespace, self.dest)
nspace = type(namespace)()
for child in self.children:
if child.default is not None:
setattr(nspace, child.name, child.default)
items[values] = nspace
class ChildAction(argparse.Action):
def __init__(self, *args, parent, sub_action='store', **kwargs):
super().__init__(*args, **kwargs)
self.dest, self.name = parent.dest, self.dest
self.action = sub_action
self._action = None
self.parent = parent
parent.children.append(self)
def get_action(self, parser):
if self._action is None:
action_cls = parser._registry_get('action', self.action, self.action)
self._action = action_cls(self.option_strings, self.name)
return self._action
def __call__(self, parser, namespace, values, option_string=None):
items = getattr(namespace, self.dest)
try:
last_item = next(reversed(items.values()))
except StopIteration:
raise argparse.ArgumentError(self, "can't be used before {}".format(self.parent.option_strings[0]))
action = self.get_action(parser)
action(parser, last_item, values, option_string)
使用 argparse,可以重复一个参数并将所有值收集到一个列表中:
parser = ArgumentParser()
parser.add_argument('-o', '--output', action='append')
args = parser.parse_args(['-o', 'output1', '-o', 'output2'])
print(vars(args))
# {'output': ['output1', 'output2']}
我正在寻找一种将标志与这些参数中的每一个相关联的方法,以便可以这样做:
args = parser.parse_args(['-o', 'output1', '--format', 'text',
'-o', 'output2', '--format', 'csv'])
并得到这样的输出(或类似的东西):
{'output': {'output1': {'format': 'text'},
'output2': {'format': 'csv'}
}
}
理想情况下,这些标志应遵循通常的语义 - 例如,--format
可以是可选的,或者可以有多个参数与每个 -o
输出相关联,在这种情况下它们应该是可以通过的以任何顺序(即 -o output1 -a -b -c
应等同于 -o output1 -c -a -b
)。
这可以用 argparse 完成吗?
只需定义 -o
接受两个参数。
parser.add_argument('-o', '--output', nargs=2, action='append')
然后-o output1 text -o output2 csv
会产生类似
的东西args = p.parse_args(['-o', 'output1', 'text', '-o', 'output2', 'csv'])
assert args.output == [['output1', 'text'], ['output2', 'csv']]
您可以 post-process args.output
以获得所需的 dict
,或者定义自定义 Action
,其 __call__
方法将构建 dict
值本身。
3 个解析器在一组通用的 -o
和 -f
标志上运行:
简单追加 - 2 dest
:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output', action='append')
parser.add_argument('-f', '--format', action='append')
args = parser.parse_args(['-o', 'output1', '-o', 'output2'])
print(args)
args = parser.parse_args(['-o', 'output1', '--format', 'text',
'-o', 'output2', '--format', 'csv'])
print(args)
args = parser.parse_args(['-o', 'output1',
'-o', 'output2', '--format', 'csv',
'-o', 'output3', '-f1', '-f2'])
print(args)
print()
nargs='+'
;将参数放在一起,但不使用 format
标志:
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output', action='append', nargs='+')
#parser.add_argument('-f', '--format', action='append')
args = parser.parse_args(['-o', 'output1', '-o', 'output2'])
print(args)
args = parser.parse_args(['-o', 'output1', 'text',
'-o', 'output2', 'csv'])
print(args)
args = parser.parse_args(['-o', 'output1',
'-o', 'output2', 'csv',
'-o', 'output3', '1', '2'])
print(args)
print()
自定义 classes 来自 append
class。为每个 output
创建一个字典。 format
修改最后一个 output
字典:
class Foo1(argparse._AppendAction):
def __call__(self, parser, namespace, values, option_string=None):
items = argparse._copy.copy(argparse._ensure_value(namespace, self.dest, []))
dd = {'output': values, 'format': []}
items.append(dd)
setattr(namespace, self.dest, items)
class Foo2(argparse._AppendAction):
def __call__(self, parser, namespace, values, option_string=None):
items = argparse._copy.copy(argparse._ensure_value(namespace, self.dest, []))
last = items[-1] # error if -f before -o
last['format'].append(values)
setattr(namespace, self.dest, items)
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output', action=Foo1)
parser.add_argument('-f', '--format', action=Foo2, dest='output')
args = parser.parse_args(['-o', 'output1', '-o', 'output2'])
print(args)
args = parser.parse_args(['-o', 'output1', '--format', 'text',
'-o', 'output2', '--format', 'csv'])
print(args)
args = parser.parse_args(['-o', 'output1',
'-o', 'output2', '--format', 'csv',
'-o', 'output3', '-f1', '-f2'])
print(args)
print()
产生:
1238:~/mypy$ python stack48504770.py
Namespace(format=None, output=['output1', 'output2'])
Namespace(format=['text', 'csv'], output=['output1', 'output2'])
Namespace(format=['csv', '1', '2'], output=['output1', 'output2', 'output3'])
Namespace(output=[['output1'], ['output2']])
Namespace(output=[['output1', 'text'], ['output2', 'csv']])
Namespace(output=[['output1'], ['output2', 'csv'], ['output3', '1', '2']])
Namespace(output=[{'output': 'output1', 'format': []},
{'output': 'output2', 'format': []}])
Namespace(output=[{'output': 'output1', 'format': ['text']},
{'output': 'output2', 'format': ['csv']}])
Namespace(output=[{'output': 'output1', 'format': []},
{'output': 'output2', 'format': ['csv']},
{'output': 'output3', 'format': ['1', '2']}])
()
基于 ParentAction
和 ChildAction
.
用法
parser = argparse.ArgumentParser()
# first, create a parent action:
parent = parser.add_argument('-o', '--output', action=ParentAction)
# child actions require a `parent` argument:
parser.add_argument('-f', '--format', action=ChildAction, parent=parent)
# child actions can be customized like all other Actions. For example,
# we can set a default value or customize its behavior - the `sub_action`
# parameter takes the place of the usual `action` parameter:
parser.add_argument('-l', '--list', action=ChildAction, parent=parent,
sub_action='append', default=[])
args = parser.parse_args(['-o', 'output1', '-l1', '-l2',
'-o', 'output2', '--format', 'csv',
'-o', 'output3', '-f1', '-f2'])
print(args)
# output (formatted):
# Namespace(
# output=OrderedDict([('output1', Namespace(list=['1', '2'])),
# ('output2', Namespace(format='csv', list=[])),
# ('output3', Namespace(format='2', list=[]))
# ])
# )
注意事项
- 子动作必须始终在父动作之后。
例如,
--format csv -o output1
将不起作用并显示一条错误消息。 不能用相同的名称注册多个 ChildActions,即使父级不同也是如此。
示例:
parent1 = parser.add_argument('-o', '--output', action=ParentAction) parser.add_argument('-f', action=ChildAction, parent=parent1) parent2 = parser.add_argument('-i', '--input', action=ParentAction) parser.add_argument('-f', action=ChildAction, parent=parent2) # throws exception: # argparse.ArgumentError: argument -f: conflicting option string: -f
代码
import argparse
from collections import OrderedDict
class ParentAction(argparse.Action):
def __init__(self, *args, **kwargs):
super().__init__(*args, default=OrderedDict(), **kwargs)
self.children = []
def __call__(self, parser, namespace, values, option_string=None):
items = getattr(namespace, self.dest)
nspace = type(namespace)()
for child in self.children:
if child.default is not None:
setattr(nspace, child.name, child.default)
items[values] = nspace
class ChildAction(argparse.Action):
def __init__(self, *args, parent, sub_action='store', **kwargs):
super().__init__(*args, **kwargs)
self.dest, self.name = parent.dest, self.dest
self.action = sub_action
self._action = None
self.parent = parent
parent.children.append(self)
def get_action(self, parser):
if self._action is None:
action_cls = parser._registry_get('action', self.action, self.action)
self._action = action_cls(self.option_strings, self.name)
return self._action
def __call__(self, parser, namespace, values, option_string=None):
items = getattr(namespace, self.dest)
try:
last_item = next(reversed(items.values()))
except StopIteration:
raise argparse.ArgumentError(self, "can't be used before {}".format(self.parent.option_strings[0]))
action = self.get_action(parser)
action(parser, last_item, values, option_string)