Python和argparse的多个位置参数

时间:2011-03-21 03:17:13

标签: python argparse

我正在尝试使用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']),但无法看到如何执行此操作 - 如果确实如此。如果有可能的话,我在文档或谷歌中看不到任何一种说法,尽管它很可能(很可能?)我忽略了一些东西。有没有人有任何建议?

4 个答案:

答案 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)

使用可选的

parser.add_argument('-i', '--input',action='append')
parser.parse_args(['-i','fileone', '-a', '-i','filetwo', '-b', '-i','filethree'])

您可以将选项与单独的位置交错('input1 -a input2 -b input3'),但不能在一个多项位置内交错选项。但是你可以通过两步解析来完成这个任务。

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'])

http://bugs.python.org/issue14191是一个建议的补丁,可以通过单次调用来执行此操作:

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。