Python 和 argparse 的多个位置参数 [英] Multiple positional arguments with Python and argparse

查看:24
本文介绍了Python 和 argparse 的多个位置参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 argparse 来解析我正在处理的程序的命令行参数.从本质上讲,我需要支持在可选参数中分布的多个位置参数,但无法让 argparse 在这种情况下工作.在实际程序中,我使用了自定义操作(每次找到位置参数时我都需要存储命名空间的快照),但是我遇到的问题可以用 append 动作:

<预><代码>>>>导入参数解析>>>解析器 = 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'])用法:ipython [-h] [-a] [-b] 输入ipython:错误:无法识别的参数:filetwo filethree

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

解决方案

srgerg 关于位置参数的定义是正确的.为了得到你想要的结果,你必须接受它们作为可选参数,并根据你的需要修改结果命名空间.

您可以使用自定义操作:

class MyAction(argparse.Action):def __call__(self, parser, namespace, values, option_string=None):# 将可选参数设置为 True 或 False如果选项字符串:attr = True if values else Falsesetattr(命名空间,self.dest,attr)# 修改命名空间中input"的值如果 hasattr(namespace, 'input'):current_values = getattr(命名空间,'输入')尝试:current_values.extend(值)除了属性错误:current_values = 值最后:setattr(命名空间,'输入',current_values)别的:setattr(命名空间,'输入',值)解析器 = 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'])命名空间(a=True, b=True, input=['fileone', 'filetwo', 'filethree'])

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

<预><代码>>>>导入参数解析>>>解析器 = argparse.ArgumentParser()>>>parser.add_argument('-a', nargs='+')>>>parser.add_argument('-b', nargs='+')>>>parser.add_argument('输入', nargs='+')>>>result = parser.parse_args(['fileone', '-a', 'filetwo', '-b', 'filethree'])>>>输入 = []>>>输入.扩展(结果.a)>>>输入.扩展(结果.b)>>>输入.扩展(结果.输入)>>>修改 = argparse.Namespace(a = 结果.a != [],b = 结果.b != [],输入 = 输入)

这就是你得到的:

<预><代码>>>>修改的命名空间(a=True, b=True, input=['filetwo', 'filethree', 'fileone'])

然而,这两种方法都会导致代码可读性和可维护性较差.也许改变程序逻辑并以不同的方式来做会更好.

I'm trying to use argparse to parse the command line arguments for a program I'm working on. Essentially, I need to support multiple positional arguments spread within the optional arguments, but cannot get argparse to work in this situation. In the actual program, I'm using a custom action (I need to store a snapshot of the namespace each time a positional argument is found), but the problem I'm having can be replicated with the append action:

>>> 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

I'd like this to result in the namespace (a=True, b=True, input=['fileone', 'filetwo', 'filethree']), but cannot see how to do this - if indeed it can. I can't see anything in the docs or Google which says one way or the other if this is possible, although its quite possible (likely?) I've overlooked something. Does anyone have any suggestions?

解决方案

srgerg was right about the definition of positional arguments. In order to get the result you want, You have to accept them as optional arguments, and modify the resulted namespace according to your need.

You can use a custom action:

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)

And this is what you get:

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

Or you can modify the resulted namespace like this:

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

And this is what you get:

>>> modified
Namespace(a=True, b=True, input=['filetwo', 'filethree', 'fileone'])

However, both method result in less readable and less maintainable code. Maybe it's better to change the program logic and do it in a different way.

这篇关于Python 和 argparse 的多个位置参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆