Python argparse 中任意数量参数的自定义解析函数 [英] Custom parsing function for any number of arguments in 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屋!