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动作,该动作将解析每个参数并将结果存储在像这样的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屋!