问题
How can I add an argument that is optional and must not be specified multiple times?
Valid:
$ ./my.py
$ ./my.py --arg MyArgValue
Invalid:
$ ./my.py --arg MyArgValue --arg ThisIsNotValid
If I add an argument like:
parser.add_argument('--arg', type=str)
The invalid example results in a string ThisIsNotValid
. I would expect a parser error.
回答1:
Create a custom action that raises an exception if the same argument is seen twice. When the parser catches the exception, it prints the usage and a nicely-formatted error message.
import argparse
class Highlander(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if getattr(namespace, self.dest, None) is not None:
raise argparse.ArgumentError(self, 'There can be only one.')
setattr(namespace, self.dest, values)
parser = argparse.ArgumentParser()
parser.add_argument('-f', action=Highlander)
print (parser.parse_args('-f 1 -f 2'.split()))
回答2:
This feels like a hacky solution, but will get you what you want. Use the append
action:
parser.add_argument('-arg', type=str, action='append')
args = parser.parse_args()
if len(args.arg) > 1:
sys.exit("Only one argument is allowed for '-arg'")
elif len(args.arg) == 1: # elif is because it is valid for the length to be 0
args.arg = args.arg[0]
The append action will create a list from the command line consisting of all the values from all the times this argument was called. If the length of this list is longer than one, there was an error.
This way you can get the values from the command line, and if there are more than one you can catch this as an error and notify the user.
回答3:
You could use this to get the number of occurences with this, and yield an error if it is more than one.
'append' - This stores a list, and appends each argument value to the list. This is useful to allow an option to be specified multiple times. Example usage:
import argparse
import sys
parser = argparse.ArgumentParser()
parser.add_argument('-arg', type='str', action='append')
args = parser.parse_args()
if len(args.arg) > 1:
sys.exit('Invalid')
MyArgValue = args.arg[0]
The documentation about 'append' can be found in here for further details:
http://docs.python.org/dev/library/argparse.html#action
Unfortunately, there is no simpler way with argparse. That is presumably because this is not a common use case enough. Usually, this count is used for boolean cases, like the verbose mode. When you have appending strings, like compilers with the include path, and so forth, they are usually all respected.
Perhaps, you could also use nargs and just use args.arg_name[0] and ignore the rest. Here you can find the nargs
documentation for that:
http://docs.python.org/dev/library/argparse.html#nargs
回答4:
I've tested a solution that uses a mutually_exclusive_group
. The idea is to define a group that includes --arg
twice. The parser maintains a seen_non_default_actions
list, and checks that for exclusive group conflicts before taking action on a new argument string. If --arg
is already present in this list, the next call would conflict with it, and raise an error.
There are couple of problems with this approach.
1) existing actions cannot be added to a new mutually_exclusive_group. In https://stackoverflow.com/a/18555236/901925 I illustrate a kludge that gets around that. It also cites a proposed patch that makes this easier.
2) currently parse_args
adds the action to the seen_non_default_actions
list, and then checks for conflicts. This means the first --arg
will conflict with itself. The solution is to switch the order. First check for conflicts, then add the action to the list.
import my_argparse as argparse # use a customized argparse
parser = argparse.ArgumentParser(prog="PROG",
formatter_class=argparse.MultiGroupHelpFormatter)
# use a custom formatter than can handle overlapping groups
action = parser.add_argument('--arg', help='use this argument only once')
# define a group with two copies of this action as per patch issue10984
group = parser.add_mutually_exclusive_group(action, action)
args = parser.parse_args()
When called with various arguments, produces:
$ python3 test.py -h
usage: PROG [-h] [--arg ARG | --arg ARG]
optional arguments:
-h, --help show this help message and exit
--arg ARG use this argument only once
$ python3 test.py --arg test
Namespace(arg='test')
$ python3 test.py --arg test --arg next
usage: PROG [-h] [--arg ARG | --arg ARG]
PROG: error: argument --arg: not allowed with argument --arg
I am wonder, though, whether this is a sufficiently intuitive way of saying, 'use this argument only once'. Does the usage line [--arg ARG | --arg ARG]
convey that? And is the error message argument --arg: not allowed with argument --arg
clear enough?
来源:https://stackoverflow.com/questions/18544468/how-to-add-optional-or-once-arguments