问题
I am designing the user interface for a command line program that needs to be able to accept one or more groups of options. Each group is the same, but needs to be linked together, like so:
./myprogram.py --group1 name1,name2,pathA,pathB --group2 name3,name4,pathC,pathD
This seems very clunky for a user to deal with. I have considered using a INI
-style configparser
setup, but it is also clunky, because I have a lot of other arguments besides this that generally have default values, and then I lose all of the power of the argparse
module for handling requirements, checking if files exist, etc.
Does anyone have any ideas on how I could best structure my ArgumentParser
so that I can get a user to provide the four required inputs for a given group, together? I am not married to the comma separated list, that was just an example. It would actually be far better if they could enter some sort of key-value pair, such as
./myprogram.py --group1 firstname:name1 secondname:name2 firstpath:pathA secondpath:pathB
But I know that argparse does not support the dict
type, and any hack to allow it would be even less user-friendly.
回答1:
You can use nargs=4
with an 'append'
action:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--group', nargs=4, action='append')
print parser.parse_args()
It'd be called as:
$ python ~/sandbox/test.py --group 1 2 3 4 --group 1 2 3 4
Namespace(group=[['1', '2', '3', '4'], ['1', '2', '3', '4']])
From here, you can parse the key-value pairs if you'd like.
Another option is to use a custom action to do the parsing -- Here's a simple one which accepts arguments of the form --group key:value key2:value2 ... --group ...
import argparse
class DictAction(argparse.Action):
def __init__(self, *args, **kwargs):
super(DictAction, self).__init__(*args, **kwargs)
self.nargs = '*'
def __call__(self, parser, namespace, values, option_string=None):
# The default value is often set to `None` rather than an empty list.
current_arg_vals = getattr(namespace, self.dest, []) or []
setattr(namespace, self.dest, current_arg_vals)
arg_vals = getattr(namespace, self.dest)
arg_vals.append(dict(v.split(':') for v in values))
parser = argparse.ArgumentParser()
parser.add_argument('--group', action=DictAction)
print parser.parse_args()
This has no checking (so the user could get funny TypeError
s if the key:value
are not formatted properly) and if you want to restrict it to specified keys, you'll need to build that in as well... but those details should be easy enough to add. You could also require that they provide 4 values using self.nargs = 4
in DictAction.__init__
.
来源:https://stackoverflow.com/questions/34930630/grouping-an-unknown-number-of-arguments-with-argparse