问题描述
我有一个python脚本,它带有一个可选的位置参数,并且有一些子命令.其中一些子命令需要位置参数,而某些则不需要.当我尝试使用不需要位置参数的子命令时,出现了我遇到的问题.考虑以下测试文件:
I have a python script that takes in an optional positional argument and has a few subcommands. Some of these subcommands require the positional argument, some don't. The problem I have appears when I try to use a subcommand that does not require the positional argument. Consider the following test file:
import argparse
argp = argparse.ArgumentParser()
argp.add_argument('inputfile', type=str, nargs='?',
help='input file to process')
argp.add_argument('--main_opt1', type=str,
help='global option')
subp = argp.add_subparsers(title='subcommands',
dest='parser_name',
help='additional help',
metavar="<command>")
tmpp = subp.add_parser('command1', help='command1 help')
tmpp.add_argument('pos_arg1', type=str,
help='positional argument')
print repr(argp.parse_args())
当我尝试将子命令command1
与第一个参数一起使用时,一切都会顺利进行.
When I try to use the subcommand command1
with the first argument everything goes well.
macbook-pro:~ jmlopez$ python pytest.py filename command1 otherarg
Namespace(inputfile='filename', main_opt1=None, parser_name='command1', pos_arg1='otherarg')
但是现在让我们假设command1
不需要第一个位置参数.
But now let us assume that command1
doesn't need the first positional argument.
macbook-pro:~ jmlopez$ python pytest.py command1 otherarg
usage: pytest.py [-h] [--main_opt1 MAIN_OPT1] [inputfile] <command> ...
pytest.py: error: argument <command>: invalid choice: 'otherarg' (choose from 'command1')
我以某种方式期望将inputfile
设置为None
. argparse
有什么方法可以预测command1
实际上是一个子命令,因此inputfile
应该设置为None?
I was somehow expecting inputfile
to be set to None
. Is there any way that argparse
can predict that command1
is actually a subcommand and thus inputfile
should be set to None?
推荐答案
对于argp
,subparser参数看起来就像另一个位置,它接受选择(子解析器的名称).同样,argp
对pos_arg1
一无所知.在tmpp
的参数列表中.
To argp
the subparser argument looks just like another positional, one that takes choices (the names of the subparsers). Also argp
knows nothing about pos_arg1
. That's in tmpp
's list of arguments.
当argp
看到filename command1 otherarg
时,filename
和command1
满足其2个位置.然后otherarg
传递到tmpp
.
When argp
sees filename command1 otherarg
, filename
and command1
satisfy its 2 positionals. otherarg
is then passed on the tmpp
.
再次使用command1 otherarg
,2个字符串,2个argp
位置. command
被分配给inputfile
.没有逻辑可以回溯并说command1
更适合subcommands
,或者说'tmpp'需要这些字符串之一.
With command1 otherarg
, again 2 strings, 2 argp
positionals. command
is assigned to inputfile
. There's no logic to backtrack and say command1
fits subcommands
better, or that `tmpp' needs one of those strings.
您可以将1st位置更改为可选的--inputfile
.
You could change the 1st positional to an optional, --inputfile
.
或者您可以inputfile
另一个位置tmpp
.如果许多子解析器需要它,请考虑使用parents
.
Or you could inputfile
another positional of tmpp
. If a number of the subparsers need it it, consider using parents
.
argparse
并不像您一样聪明,也不能想先"或后退".如果它看起来做得很聪明,那是因为它使用re
模式匹配来处理nargs
值(例如?,*,+).
argparse
isn't a smart as you, and can't 'think ahead' or 'backtrack'. If it appears to do something smart it's because it uses re
pattern matching to handle nargs
values (e.g. ?, *, +).
编辑
诱骗" argparse将其识别为子解析器的第一个位置的一种方法是在其后插入一个可选内容.使用command1 -b xxx otherarg
时,-b xxx
分解位置字符串的列表,因此只有command1
与inputfile
和subcommands
相匹配.
One way to 'trick' argparse into recognizing the first positional as the subparser is to insert an optional after it. With command1 -b xxx otherarg
, -b xxx
breaks up the list of positional strings, so only command1
is matched against inputfile
and subcommands
.
p=argparse.ArgumentParser()
p.add_argument('file',nargs='?',default='foo')
sp = p.add_subparsers(dest='cmd')
spp = sp.add_parser('cmd1')
spp.add_argument('subfile')
spp.add_argument('-b')
p.parse_args('cmd1 -b x three'.split())
# Namespace(b='x', cmd='cmd1', file='foo', subfile='three')
这里的问题是argparse
如何处理具有变量nargs
的位置.第二个位置是次解析器这一事实并不重要.尽管argparse
允许以任何顺序可变长度的位置,但它如何处理它们却可能造成混淆.如果只有一个这样的位置,并且在末尾出现,则更容易预测argparse
将要执行的操作.
The issue here is how argparse
handles postionals with variable nargs
. The fact that the 2nd positional is a subparser is not important. While argparse
allows variable length positionals in any order, how it handles them can be confusing. It's easier to predict what argparse
will do if there is only one such positional, and it occurs at the end.
这篇关于argparse可选的位置参数和子解析器参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!