2015-11-11 134 views
4

当使用argparse时,一些子命令需要相同的选项,我使用parents来避免在每个子命令中重复定义它们。如何将通用参数添加到argparse子命令?

脚本文件名:testarg.py

import argparse                 

parser = argparse.ArgumentParser(add_help=False)         
parser.add_argument('-H', '--host', default='192.168.122.1')      
parser.add_argument('-P', '--port', default='12345')        
subparsers = parser.add_subparsers()            

# subcommand a                 
parser_a = subparsers.add_parser('a', parents=[parser])       
parser_a.add_argument('-D', '--daemon', action='store_true')      

parser_a.add_argument('-L', '--log', default='/tmp/test.log')      

# subcommand b                 
parser_b = subparsers.add_parser('b', parents=[parser])       
parser_b.add_argument('-D', '--daemon', action='store_true')      

# subcommand c                 
parser_c = subparsers.add_parser('c', parents=[parser])       
args = parser.parse_args()              

print args 

但是当我运行命令:

>>>./testarg.py a 
usage: testarg.py a [-h] [-H HOST] [-P PORT] [-D] [-L LOG] {a,b,c} ... 
testarg.py a: error: too few arguments 

预期输出:

>>>./testarg.py a 
Namespace(daemon=False, host='192.168.122.1', log='/tmp/test.log', port='12345') 

>>>./testarg.py b -H 127.0.0.1 -P 11111 
Namespace(daemon=False, host='127.0.0.1', port='11111') 

>>>./testarg.py c 
Namespace(host='192.168.122.1', port='12345') 

also, 

>>>./testarg.py c -H 127.0.0.1 -P 12222 
Namespace(host='127.0.0.1', port='12222') 

我缺少什么?

+0

你能解释一下你想达到的目标吗? – Alik

+0

@Alik,答案已更新。我想用相同的选项('-H','-P')运行一些子命令,但我不想将它们添加到每个子命令中。 –

回答

14

创建一个独立的母公司解析器和它传递给subparsers

import argparse                 

parent_parser = argparse.ArgumentParser(add_help=False)         
parent_parser.add_argument('-H', '--host', default='192.168.122.1')      
parent_parser.add_argument('-P', '--port', default='12345')        

parser = argparse.ArgumentParser(add_help=False) 
subparsers = parser.add_subparsers()            

# subcommand a                 
parser_a = subparsers.add_parser('a', parents = [parent_parser])       
parser_a.add_argument('-D', '--daemon', action='store_true')      

parser_a.add_argument('-L', '--log', default='/tmp/test.log')      

# subcommand b                 
parser_b = subparsers.add_parser('b', parents = [parent_parser])       
parser_b.add_argument('-D', '--daemon', action='store_true')      

# subcommand c                 
parser_c = subparsers.add_parser('c', parents = [parent_parser])       
args = parser.parse_args()              

print args 

当您使用parser本身作为subparsers的parents这使期望的结果

$ python arg.py a 
Namespace(daemon=False, host='192.168.122.1', log='/tmp/test.log', port='12345') 
$ python arg.py b -H 127.0.0.1 -P 11111 
Namespace(daemon=False, host='127.0.0.1', port='11111') 
$ python arg.py c 
Namespace(host='192.168.122.1', port='12345') 
+0

谢谢,它的工作原理。我阅读官方的argparse文档,但没有找出方法,你怎么知道这一点?任何文档? –

+0

该文档有一个“父母”部分和一个“subparsers”部分,您已阅读。你正在以一种意想不到的方式把它们放在一起很难预测所有的应用程序。 – hpaulj

5

,你递归增加subparsers每个子分析器。 add_subparsers命令实际上定义了一个位置参数,一个可以选择的位置参数{'a','b','c'}。它最终会期待prog.py a a a ...,每个子分析器都期望另一个子分析器命令等。

我从来没有见过任何人尝试过这种定义,并且花了一些时间来思考发生了什么。

@Alik's方法是正确的。分别定义父解析器,不要直接使用它。它只是那些-H-P要添加到每个子分析器的操作的源代码。这就是你想要添加到子分析器中的全部内容。

另一种方法是在主解析器中简单定义-H-P

parser = argparse.ArgumentParser() 
parser.add_argument('-H', '--host', default='192.168.122.1') 
parser.add_argument('-P', '--port', default='12345') 
subparsers = parser.add_subparsers() 

# subcommand a 
parser_a = subparsers.add_parser('a') 
parser_a.add_argument('-D', '--daemon', action='store_true') 
.... 

它会以同样的方式运行,除了-H-P则要子分析器命令之前指定。

0015:~/mypy$ python stack33645859.py -H 127.0.0.1 -P 1111 b 
Namespace(daemon=False, host='127.0.0.1', port='1111') 

它们仍然以同样的方式出现在命名空间中,它只是在命令行中的顺序不同。 help也会有所不同。

第三个选项是以编程方式添加通用参数,并带有循环或函数。粗的例子是:

parser = argparse.ArgumentParser() 
subparsers = parser.add_subparsers() 
splist = [] 
for cmd in ['a','b','c']: 
    p = subparsers.add_parser(cmd) 
    p.add_argument('-H', '--host', default='192.168.122.1') 
    p.add_argument('-P', '--port', default='12345') 
    splist.append(p) 
splist[0].add_argument('-D', '--daemon', action='store_true') 

功能这将是类似于@Alik's方法,将具有一个微妙的差异。通过parent,只创建一对HP动作对象。引用被添加到每个子分析器。

与我的一样,每个子分析器都有自己的HP动作对象。每个子分析器都可以为这些参数定义不同的defaults。我记得这是另一个SO问题。

编码工作是在所有情况下类似。

+0

感谢您的优秀解释。非常感谢。其实,我尝试了你建议的两种方法。我问这些问题是因为我认为-P和-H是每个子命令的一部分,但不是根分析器,在子命令不是我想要的之前,必须指定-H和-P。你有任何关于如何执行pythonic常用选项的子命令的建议吗? –

+0

我的最后一个建议对我来说看起来相当pythonic。 – hpaulj

相关问题