如何为argparse子命令添加公共参数?

Fuj*_*Liu 6 python python-2.7 argparse

使用argparse时,一些子命令需要相同的选项,我用它parents来避免在每个子命令中重复定义它们.

脚本文件名: 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   
Run Code Online (Sandbox Code Playgroud)

但是当我运行命令时:

>>>./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
Run Code Online (Sandbox Code Playgroud)

期待输出:

>>>./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')
Run Code Online (Sandbox Code Playgroud)

我错过了什么?

Ali*_*lik 22

创建一个单独的父解析器并将其传递给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   
Run Code Online (Sandbox Code Playgroud)

这给出了期望的结果

$ 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')
Run Code Online (Sandbox Code Playgroud)

  • 我需要“parent_parser”的“add_help=False”,但不需要“parser”。如果父解析器上没有这个,它会抛出错误。在 `parent_parser` 上设置 `add_help=False` 不会阻止父解析器选项在 `parser` 的 --help 中列出。 (2认同)

hpa*_*ulj 5

当您将parser自己用作子parents分析符时,可以递归地添加subparsers到每个子分析符.该add_subparsers命令实际上定义了一个位置参数,一个获得选择的参数{'a','b','c'}.它最终期待prog.py a a a ...,每个subparser期望另一个subparser命令等.

我从未见过有人尝试这种定义,并且需要一些思考才能意识到发生了什么.

@Alik's方法是正确的.单独定义父解析器,不要直接使用它.它只是您想要添加到每个subparser的那些-H-PActions 的源.这就是你想要添加到subparsers的所有内容.

另一种方法是简单地定义-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')
....
Run Code Online (Sandbox Code Playgroud)

它会以同样的方式运作,但-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')
Run Code Online (Sandbox Code Playgroud)

它们仍以相同的方式出现在命名空间中,只是命令行中的顺序不同. 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')
Run Code Online (Sandbox Code Playgroud)

在功能上它将类似于@Alik's方法,具有细微差别.使用parent,只创建一对HPAction对象.引用被添加到每个子分析器.

随着矿井,每个子分析器都有自己HPAction对象.每个subparser可以defaults为这些参数定义不同的.我记得这是另一个问题中的一个问题.

编码工作在所有情况下都类似.