Pass an optional list to argparse

时间秒杀一切 提交于 2019-12-25 05:26:11

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!