我正在尝试使用argparse来解析我正在处理的程序的命令行参数。本质上,我需要支持在可选参数中传播的多个位置参数,但是在这种情况下无法使argparse工作。在实际程序中,我正在使用自定义操作(我需要在每次找到位置参数时存储命名空间的快照),但我可以使用append
操作复制我遇到的问题:
>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('-a', action='store_true')
>>> parser.add_argument('-b', action='store_true')
>>> parser.add_argument('input', action='append')
>>> parser.parse_args(['fileone', '-a', 'filetwo', '-b', 'filethree'])
usage: ipython [-h] [-a] [-b] input
ipython: error: unrecognized arguments: filetwo filethree
我希望这会导致名称空间(a=True, b=True, input=['fileone', 'filetwo', 'filethree'])
,但无法看到如何执行此操作 - 如果确实如此。如果有可能的话,我在文档或谷歌中看不到任何一种说法,尽管它很可能(很可能?)我忽略了一些东西。有没有人有任何建议?
答案 0 :(得分:18)
您不能以这种方式将开关(即-a
和-b
)与位置参数(即fileone,filetwo和filethree)交错。开关必须出现在位置参数之前或之后,而不是介于两者之间。
此外,为了拥有多个位置参数,您需要将nargs
参数指定为add_argument
。例如:
parser.add_argument('input', nargs='+')
这告诉argparse
使用一个或多个位置参数并将它们附加到列表中。有关详细信息,请参阅argparse documentation。使用此行,代码:
parser.parse_args(['-a', '-b', 'fileone', 'filetwo', 'filethree'])
结果:
Namespace(a=True, b=True, input=['fileone', 'filetwo', 'filethree'])
答案 1 :(得分:10)
srgerg对位置论证的定义是对的。为了获得您想要的结果,您必须接受它们作为可选参数,并根据您的需要修改结果命名空间。
您可以使用自定义操作:
class MyAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
# Set optional arguments to True or False
if option_string:
attr = True if values else False
setattr(namespace, self.dest, attr)
# Modify value of "input" in the namespace
if hasattr(namespace, 'input'):
current_values = getattr(namespace, 'input')
try:
current_values.extend(values)
except AttributeError:
current_values = values
finally:
setattr(namespace, 'input', current_values)
else:
setattr(namespace, 'input', values)
parser = argparse.ArgumentParser()
parser.add_argument('-a', nargs='+', action=MyAction)
parser.add_argument('-b', nargs='+', action=MyAction)
parser.add_argument('input', nargs='+', action=MyAction)
这就是你得到的:
>>> parser.parse_args(['fileone', '-a', 'filetwo', '-b', 'filethree'])
Namespace(a=True, b=True, input=['fileone', 'filetwo', 'filethree'])
或者您可以像这样修改结果命名空间:
>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('-a', nargs='+')
>>> parser.add_argument('-b', nargs='+')
>>> parser.add_argument('input', nargs='+')
>>> result = parser.parse_args(['fileone', '-a', 'filetwo', '-b', 'filethree'])
>>> inputs = []
>>> inputs.extend(result.a)
>>> inputs.extend(result.b)
>>> inputs.extend(result.input)
>>> modified = argparse.Namespace(
a = result.a != [],
b = result.b != [],
input = inputs)
这就是你得到的:
>>> modified
Namespace(a=True, b=True, input=['filetwo', 'filethree', 'fileone'])
但是,这两种方法都会导致代码的可读性和可维护性降低。也许最好改变程序逻辑并以不同的方式进行。
答案 2 :(得分:3)
使用可选的 您可以将选项与单独的位置交错('input1 -a input2 -b input3'),但不能在一个多项位置内交错选项。但是你可以通过两步解析来完成这个任务。 http://bugs.python.org/issue14191是一个建议的补丁,可以通过单次调用来执行此操作:parser.add_argument('-i', '--input',action='append')
parser.parse_args(['-i','fileone', '-a', '-i','filetwo', '-b', '-i','filethree'])
import argparse
parser1 = argparse.ArgumentParser()
parser1.add_argument('-a', action='store_true')
parser1.add_argument('-b', action='store_true')
parser2 = argparse.ArgumentParser()
parser2.add_argument('input', nargs='*')
ns, rest = parser1.parse_known_args(['fileone', '-a', 'filetwo', '-b', 'filethree'])
# Namespace(a=True, b=True), ['fileone', 'filetwo', 'filethree']
ns = parser2.parse_args(rest, ns)
# Namespace(a=True, b=True, input=['fileone', 'filetwo', 'filethree'])
parser.parse_intermixed_args(['fileone', '-a', 'filetwo', '-b', 'filethree'])
答案 3 :(得分:2)
在我看来,hpaulj走在正确的轨道上,但让事情变得比必要的复杂一点。我怀疑Blair正在寻找类似于旧的optparse模块行为的东西,并且不需要args对象的输入字段中的输入参数列表。他只想要
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-a', action='store_true')
parser.add_argument('-b', action='store_true')
opts, args = parser.parse_known_args(['fileone', '-a', 'filetwo', '-b', 'filethree'])
# Namespace(a=True, b=True), ['fileone', 'filetwo', 'filethree']
在optparse的白话中,"选项"在opts中可用,以及可能散布的其他"参数"在args。