问题
Is there a more elegant way to pass an optional list of integers to argparse
than to pass a delimited string and parse it later? I also have a positional argument.
parser.add_argument('--ids', type=int, nargs='+')
parser.add_argument('cmd')
doesn't work, because argparse
attempts to grab cmd
and complains that it isn't an integer.
Ideally, I'd like to execute with one of
program.py --ids 6,32,12 refresh
program.py --ids 6 32 12 refresh
or something similar, but also be able to
program.py refresh
回答1:
If you just want to parse arguments of the form --ids 1,2,3
(no whitespace), you can use something like this:
def convert(argument):
return map(int, argument.split(',')) # 3.x: consider wrapping in list()
parser.add_argument('--ids', type=convert)
This will not handle arguments separated by whitespace, though you could probably mitigate that somewhat with a smarter convert()
function. You would then need to quote them, however, or else the shell would pass them as separate arguments.
回答2:
--
is a handy way of saying 'positional arguments start here'.
With your parser, these work:
program.py refresh # sets ids=None
program.py refresh --ids 1 2 3
program.py --ids 1 2 3 -- refresh
You could give the --ids
argument a default (e.g. []) if you don't like the None
.
Any problems with program.py refesh --ids 1,2,3
are due to how the shell splits your command line. Look at the sys.argv
list.
Problems with program.py --ids 1 2 3 refresh
arise because when handling --ids
, the parser tries to use all strings that follow that aren't obviously flags (e.g. with '-'). It does not use the 'int' type to test which ones to use and which to leave.
Now if the ids
were positional, it would handle the 1 2 3 refresh
:
parser.add_argument('ids',type=int,nargs='+')
parser.add_argument('cmd')
parser.parse_args('1 2 3 refresh'.split())
But that's because the parser uses a different strategy to allocate strings to several positional arguments. It uses a re
matcher that looks like A+A
.
Kevin's type
approach might be better implemented with a simple function:
def mytype(astring):
ll = astring.split(',')
return [int(l) for l in ll]
parser.add_argument('--ids', type=mytype)
It could be generalized to handle quoted strings like "1 2 3". type
can be any function that takes a string, and returns the desired value(s), and raises an error if it can't do the conversion.
来源:https://stackoverflow.com/questions/29038751/pass-an-optional-list-to-argparse