Python 分析多个子parser,但使用全局参数

Python 分析多个子parser,但使用全局参数,python,argparse,Python,Argparse,我已经阅读了很多关于如何定义、解析和运行多个子parser来运行类似的东西的问题和答案 tool.py func_a -a 12 func_b -b 15 input.txt output.txt ^-- main parser args ^--------------- subparser b ^---------------------------- subparse

我已经阅读了很多关于如何定义、解析和运行多个子parser来运行类似的东西的问题和答案

tool.py func_a -a 12 func_b -b 15 input.txt output.txt
                                  ^-- main parser args
                     ^--------------- subparser b
        ^---------------------------- subparser a
他们通常建议如下:

def func_a(args):
    pass

def func_b(args):
    pass


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

# Define subparsers
subp_a = subparsers.add_parser(func_a.__name__)
subp_a.set_defaults(func=func_a)
subp_a.add_argument('-a')

subp_b = subparsers.add_parser(func_b.__name__)
subp_b.set_defaults(func=func_b)
subp_b.add_argument('-b')

# Define global parameters
parser.add_argument('input', type=argparse.FileType('r'))
parser.add_argument('output', type=argparse.FileType('wb', 0))

# Parse and run through all arguments
rest = sys.argv[1:]
while rest:
    args, rest = parser.parse_known_args(rest)
    args.func(args)
但是这个实现有一个问题:参数
input
output
是为主解析器定义的,应该只使用一次。但是,
parser.parse\u known\u args(rest)
的每次调用都需要设置值,并因此将其从
rest
中删除

这意味着对
parse_known_args
的第一次调用将检索值,随后的每个调用都会由于缺少参数而失败


是否有一种解决方案可以在不手动将值复制到
rest
列表的情况下克服此问题?

是的,第一个
parse_known_args
使用文件名和第一个子parser级别

您可以定义两个解析器,一个具有“全局”位置,另一个不具有。首先使用“with”解析器解析,挂起它的
args
(用于文件名)。然后使用'without'解析器沿着子parser堆栈进行分析

下面是一个简单的例子:

parser = argparse.ArgumentParser()
parser.add_argument('foo')
subp = parser.add_subparsers(dest='cmd')
cmd1 = subp.add_parser('cmd1')
cmd1.add_argument('-a')
cmd2 = subp.add_parser('cmd2')
# parser.add_argument('bar')  # confusing location

parser1 = argparse.ArgumentParser()
subp = parser1.add_subparsers(dest='cmd')
cmd1 = subp.add_parser('cmd1', parents=[cmd1], add_help=False)
cmd2 = subp.add_parser('cmd2')

# Parse and run through all arguments
args, rest = parser.parse_known_args()
print args, rest
while rest:
    args, rest = parser1.parse_known_args(rest)
    print args, rest
我把
解析器
foo
放在
subp
之前,因为它在那里产生的混乱更少。末尾的位置(
)可能与其中一个子parser或其中一个嵌套子parser的参数混淆,尤其是在生成错误消息时

要了解
parse_args
如何将参数字符串分配到各个位置,请尝试以下脚本:

parser = argparse.ArgumentParser()
parser.add_argument('foo')
parser.add_argument('cmd', nargs=argparse.PARSER, choices=['cmd1','cmd2']) 
parser.add_argument('bar') 
print parser.parse_args()
对于
解析器
,subparsers参数看起来就像至少包含一个字符串的位置(有点像
'+'
),第一个必须匹配
选项
。它将接收所有“剩余”字符串,与其他位置的要求一致