Python和argparse的多个位置参数

Bla*_*air 24 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
Run Code Online (Sandbox Code Playgroud)

我希望这会导致命名空间(a=True, b=True, input=['fileone', 'filetwo', 'filethree']),但无法看到如何做到这一点 - 如果它确实可以.如果有可能的话,我在文档或谷歌中看不到任何一种说法,尽管它很可能(很可能?)我忽略了一些东西.有没有人有什么建议?

srg*_*erg 19

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

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

parser.add_argument('input', nargs='+')
Run Code Online (Sandbox Code Playgroud)

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

parser.parse_args(['-a', '-b', 'fileone', 'filetwo', 'filethree'])
Run Code Online (Sandbox Code Playgroud)

结果是:

Namespace(a=True, b=True, input=['fileone', 'filetwo', 'filethree'])
Run Code Online (Sandbox Code Playgroud)

  • 是的,但正如我在答案的开头解释的那样,你不能将开关(例如`-a`)与位置参数(例如fileone,filetwo,...)交错.你_must_在位置参数之前或之后放置开关. (2认同)

Wan*_*wei 11

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)
Run Code Online (Sandbox Code Playgroud)

这就是你得到的:

>>> parser.parse_args(['fileone', '-a', 'filetwo', '-b', 'filethree'])
Namespace(a=True, b=True, input=['fileone', 'filetwo', 'filethree'])
Run Code Online (Sandbox Code Playgroud)

或者您可以像这样修改结果命名空间:

>>> 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)
Run Code Online (Sandbox Code Playgroud)

这就是你得到的:

>>> modified
Namespace(a=True, b=True, input=['filetwo', 'filethree', 'fileone'])
Run Code Online (Sandbox Code Playgroud)

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


hpa*_*ulj 5

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

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

您可以将选项与单独的位置 ('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'])
Run Code Online (Sandbox Code Playgroud)

http://bugs.python.org/issue14191是一个提议的补丁,它可以通过一次调用来做到这一点:

parser.parse_intermixed_args(['fileone', '-a', 'filetwo', '-b', 'filethree'])
Run Code Online (Sandbox Code Playgroud)