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

查看:28
本文介绍了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 操作,它将解析每个参数并将结果存储在一个字典中,例如:

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='*' 对以下语法有意义:

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天全站免登陆