38

我正在尝试使用 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

4 回答 4

31

您不能以这种方式将开关(即-a-b)与位置参数(即 fileone、filetwo 和 filethree)交错。开关必须出现在位置参数之前或之后,而不是介于两者之间。

此外,为了有多个位置参数,您需要将nargs参数指定为add_argument. 例如:

parser.add_argument('input', nargs='+')

这告诉argparse使用一个或多个位置参数并将它们附加到列表中。有关详细信息,请参阅argparse 文档。有了这一行,代码:

parser.parse_args(['-a', '-b', 'fileone', 'filetwo', 'filethree'])

结果是:

Namespace(a=True, b=True, input=['fileone', 'filetwo', 'filethree'])
于 2011-03-21T03:32:34.953 回答
17

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

但是,这两种方法都会导致代码的可读性和可维护性降低。也许最好改变程序逻辑并以不同的方式进行。

于 2011-03-21T05:42:21.263 回答
5

使用可选的“附加”操作更有意义:

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'])
于 2013-07-31T03:19:32.793 回答
3

在我看来,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 中。

于 2017-07-06T15:56:11.817 回答