Python argparse中任意数量的参数的自定义解析函数 [英] Custom parsing function for any number of arguments in Python argparse

查看:207
本文介绍了Python argparse中任意数量的参数的自定义解析函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个脚本,可以通过命令行获取命名参数.参数之一可以多次提供.例如,我想运行一个脚本:

I have a script that gets named parameters via command-line. One of arguments may be supplied multiple times. For example I want to run a script:

./script.py --add-net=user1:10.0.0.0/24 --add-net=user2:10.0.1.0/24 --add-net=user3:10.0.2.0/24

现在,我想执行一个argparse动作,该动作将解析每个参数并将结果存储在像这样的dict中:

Now I want to have an argparse action that will parse every parameter and store results in a dict like:

{ 'user1': '10.0.0.0/24',
  'user2': '10.0.1.0/24',
  'user3': '10.0.2.0/24' }

此外,如果没有提供任何值,则应该提供一个默认值.喜欢

Also there should be a default value that will be supplied if there's no value provided. Like

./script.py

应该有这样的格言:

{'user': '192.168.0.0/24'}

我认为我必须为argparse建立一个自定义动作.我想出的是:

I believe that I have to build a custom action for argparse. What I came up with is:

class ParseIPNets(argparse.Action):
    """docstring for ParseIPNets"""
    def __init__(self, option_strings, dest, nargs=None, **kwargs):
        super(ParseIPNets, self).__init__(option_strings, dest, **kwargs)

    def __call__(self, parser, namespace, values, option_string=None):
        for value in values:
            location, subnet = values.split(':')
            namespace.user_nets[location] = subnet

parser = argparse.ArgumentParser(description='foo')
parser.add_argument('--add-net',
                    nargs='*',
                    action=ParseIPNets,
                    dest='user_nets',
                    help='Nets subnets for users. Can be used multiple times',
                    default={"user1": "198.51.100.0/24"})

args = parser.parse_args()

当我需要使用默认值时,效果很好:

That works fine when I need to use default value:

test.py
Namespace(user_nets={'user1': '198.51.100.0/24'})

但是,当我添加参数时-它们会附加到默认值之后.我的期望是应将它们添加到空字典中:

However when I add parameters - they got appended to default value. My expectation is that they should be added to an empty dict:

test.py --add-net=a:10.0.0.0/24 --add-net=b:10.1.0.0/24
Namespace(user_nets={'a': '10.0.0.0/24', 'b': '10.1.0.0/24', 'user1': '198.51.100.0/24'})

达到我所需要的正确方法是什么?

What's the right way to reach what I need?

推荐答案

很明显,argparse在内部将默认值作为结果对象的初始值,因此您不应在add_argument调用中直接设置默认值但要做一些额外的处理:

As it is clear that argparse internally puts the default as initial value of the resulting object, you should not directly set the default in the add_argument call but do some extra processing:

parser.add_argument('--add-net',
                    action=ParseIPNets,
                    dest='user_nets',
                    help='Nets subnets for users. Can be used multiple times',
                    default = {})

args = parser.parse_args()
if len(args.user_nets) == 0:
    args.user_nets['user1'] = "198.51.100.0/24"

或者,如果您希望获得更好的用户体验,则可以利用Python处理可变默认参数的方式:

Alternatively, if you want a better user experience, you could make use of the way Python processes mutable default arguments:

class ParseIPNets(argparse.Action):
    """docstring for ParseIPNets"""
    def __init__(self, option_strings, dest, nargs=None, **kwargs):
        super(ParseIPNets, self).__init__(option_strings, dest, **kwargs)
    def __call__(self, parser, namespace, values, option_string=None, first=[True]):
        if first[0]:
            namespace.user_nets.clear()
            first[0] = False
        location, subnet = values.split(':')
        namespace.user_nets[location] = subnet

parser.add_argument('--add-net',
                    action=ParseIPNets,
                    dest='user_nets',
                    help='Nets subnets for users. Can be used multiple times',
                    default={"user1": "198.51.100.0/24"})

args = parser.parse_args()

这样,如果存在该选项,则将清除可选默认值.

That way, the optional default will be cleared if the option is present.

但是注意:仅在首次调用脚本时有效.这是可以接受的,因为parser.parse_args()只能在脚本中调用一次.

But BEWARE: this will work only at first call on the script. It is acceptable here because parser.parse_args() should only be called once in a script.

旁白:我删除了nargs='*',因为如果您这样称呼它,我发现它比这里有用的危险更大,并且还始终使用values删除了values上的错误循环:

Ancilliary remark: I removed nargs='*' because I find it more dangerous than useful here if you call it that way, and also removed the erroneous loop over values always using values:

test.py --add-net=a:10.0.0.0/24 --add-net=b:10.1.0.0/24

nargs='*'对于以下语法有意义:

nargs='*' would make sense for following syntax:

test.py --add-net a:10.0.0.0/24 b:10.1.0.0/24

,代码为:

    def __call__(self, parser, namespace, values, option_string=None, first=[True]):
        if first[0]:
            namespace.user_nets.clear()
            first[0] = False
        for value in values:
            location, subnet = value.split(':')
            namespace.user_nets[location] = subnet

这篇关于Python argparse中任意数量的参数的自定义解析函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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