我正在使用argparse构建一个带有子命令的命令:
mycommand [GLOBAL FLAGS]子命令[FLAGS]
我希望全局标志能够工作,无论它们是在子命令之前还是之后。有没有一种干净的方法可以做到这一点,不涉及重复代码?
例如:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subparser_name')
parser.add_argument('--disable') # This flag...
sp = subparsers.add_parser('compile')
sp.add_argument('zones', nargs='*')
sp.add_argument('--disable') # Is repeated...
sp = subparsers.add_parser('launch')
sp.add_argument('zones', nargs='*')
sp.add_argument('--disable') # over and over...
我想为许多旗帜做这件事,所以一遍又一遍地重复自己似乎...... unpythonic。
答案 0 :(得分:11)
这是parents
argparse功能的完美用例:
有时,一些解析器共享一组共同的参数。宁 比重复这些参数的定义,一个解析器 与所有共享参数一起传递给parents =参数 可以使用ArgumentParser。
定义基本父ArgumentParser
,添加将在子分析符之间共享的参数。然后,通过提供parents
关键字参数,添加子分析器并将基本分析器设置为父分析器:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subparser_name')
base_subparser = argparse.ArgumentParser(add_help=False)
# define common shared arguments
base_subparser.add_argument('--disable')
sp = subparsers.add_parser('compile', parents=[base_subparser])
# define custom arguments
sp = subparsers.add_parser('launch', parents=[base_subparser])
# define custom arguments
请注意,add_help=False
此处有助于避免conflicting help
argument出现问题。
答案 1 :(得分:1)
您要求使用argparse解决方案,但是当您还要求使用Pythonic解决方案时,我会故意使用包docopt
提出替代方案:
得到它:
$ pip install docopt
将您的代码写入mycommand
文件:
"""
Usage:
mycommand compile [--disable] <zone>...
mycommand launch [--disable] <zone>...
Arguments:
<zone> zone name
Options:
-h --help
--disable disable
"""
from docopt import docopt
if __name__ == "__main__":
args = docopt(__doc__)
print args
然后从命令行调用它:
基本帮助(无参数):
$ python mycommand
Usage:
mycommand compile [--disable] <zone>...
mycommand launch [--disable] <zone>...
寻求帮助:
$ python mycommand -h
Usage:
mycommand compile [--disable] <zone>...
mycommand launch [--disable] <zone>...
Arguments:
<zone> zone name
Options:
-h --help
--disable disable
使用compile子命令:
$ python mycommand compile zoneAlfa zoneBeta
{'--disable': False,
'<zone>': ['zoneAlfa', 'zoneBeta'],
'compile': True,
'launch': False}
添加标志--disable:
$ python mycommand compile --disable zoneAlfa zoneBeta
{'--disable': True,
'<zone>': ['zoneAlfa', 'zoneBeta'],
'compile': True,
'launch': False}
launch子命令也适用:
$ python mycommand launch --disable zoneAlfa zoneBeta
{'--disable': True,
'<zone>': ['zoneAlfa', 'zoneBeta'],
'compile': False,
'launch': True}
我对参数解析器的使用也是以argparse开头的,我讨厌代码的复杂性,这是做某事所需要的。
后来我转向plac
,这是将python函数转换为非常有用的控制台命令的非常有效的方法。
尽管如此,我受限于遵循和理解的规则,在许多情况下我并不十分清楚。使用docopt
我很感激,我可以按照POSIX的标准规则首先编写文档字符串,然后在我的代码中使用它。如果您关心参数的验证,我会指导您阅读这个伟大的包的样本。
答案 2 :(得分:1)
我在你的例子中看到两个问题:
1)在解析器和子解析器中使用'--disable'。 Nested ArgumentParser
处理重叠dest
。
2)subsparsers中重复的一组参数。 parents
肯定是简化这一点的一种方法。但您可以轻松编写自己的代码:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subparser_name')
parser.add_argument('--disable', dest='main_disable') # This flag...
for name in ['compile', 'launch']:
sp = subparsers.add_parser(name)
sp.add_argument('zones', nargs='*')
sp.add_argument('--disable', dest=name+'_disable') # Is repeated...