您的描述和代码很难遵循,但我已经断定您的问题在于主和子分析器共享参数dest
时如何处理默认值。
我凝聚你的代码了一点,所以我可以做一个测试运行:
import argparse
class Parsing(object):
def __init__(self):
self.parser = argparse.ArgumentParser(prog='prog',
description='some description')
self.subparser = self.parser.add_subparsers(dest='cmd', title='Cmds', help='help description')
self.make_subparsers(['cmd1','cmd2'])
def make_subparsers(self, parsers):
for each in parsers:
subp = self.subparser.add_parser(each)
self.optional(subp, default='sub')
self.optional(self.parser, default='main')
def optional(self, parser, default=None):
parser.add_argument('--foo', default=default)
args = Parsing().parser.parse_args()
print(args)
我得到2个运行
1315:~/mypy$ python3.5 stack41431025.py cmd1 --foo 1
Namespace(cmd='cmd1', foo='1')
1316:~/mypy$ python3.5 stack41431025.py --foo 1 cmd1
Namespace(cmd='cmd1', foo='sub')
在第一,foo
是通过解析字符串设定cmd1
subparser。
第二,foo
获取由subparser设置的默认值。主分析器解析为--foo
,但其值已由分析器重写。
有一些关于bug /问题的讨论。 http://bugs.python.org/issue9351更改了处理方式,以便子分析器默认优先于主分析器值。我认为这个补丁存在问题,但它已经生效了几年。
如果给予不同的dest
,您会保留更多控制权。
def make_subparsers(self, parsers):
for each in parsers:
subp = self.subparser.add_parser(each)
self.optional(subp, default='sub')
self.optional(self.parser, default='main', dest='main_foo')
def optional(self, parser, default=None, dest=None):
parser.add_argument('--foo', default=default, dest=dest)
1325:~/mypy$ python3.5 stack41431025.py --foo 1 cmd1
Namespace(cmd='cmd1', foo='sub', main_foo='1')
1325:~/mypy$ python3.5 stack41431025.py cmd1
Namespace(cmd='cmd1', foo='sub', main_foo='main')
1325:~/mypy$ python3.5 stack41431025.py --foo 1 cmd1 --foo 2
Namespace(cmd='cmd1', foo='2', main_foo='1')
====================
(刚才的答复)
我会尽力勾勒出参数的可能组合
parser = argparse.ArgumentParser()
parser.add_argument('mainpos', help='positional for main')
parser.add_argument('--mainopt', help='optional defined for main')
sp = parser.add_subparser(dest='cmd')
p1 = sp.add_parser('cmd1')
p1.add_argument('subpos', help='postional for sub')
p1.add_argument('--subopt', help='optional defined for sub')
复合usage
会是什么样子:
python prog.py foo [--mainopt bar] cmd1 sfoo [--subopt baz]
各自的positionals
必须以正确的顺序给出。子分析器cmd
实际上是main
的位置。
为main定义的可选项必须发生在子分析器名称之前。为子分析器定义的可选项必须发生在之后。他们可以有相同的flag
或dest
,但他们必须单独定义。如果它们具有相同的dest
,则可能会发生数值冲突,尤其是默认值。
parser.parse_args()
开始将输入字符串与其参数进行匹配。如果它看到--mainopt
正在解析该可选参数。否则,它期望两个postionals。第二个必须是子分析器名称之一。
一旦它得到一个子分析器名称,它会将剩余的字符串传递给该子分析器。子分析器处理其余部分,并将这些值放在主名称空间中。而且分析器的第一件事是设置其默认值。该动作是否覆盖主分析器设置的值取决于两者之间如何传递namespace
。
================
解析是通过在命令行参数的顺序驱动。它试图允许以任何顺序标记参数。但是一旦解析被传递给子解析器,主解析器就不会再解析了。它只是做一些清理任务。
但是,如果我使用parse_known_args
,我可以收集这两个解析器都没有处理的字符串,并采取另一个解析它们的方法。
parser1 = argparse.ArgumentParser()
parser1.add_argument('--foo')
sp = parser1.add_subparsers(dest='cmd')
sp1 = sp.add_parser('cmd1')
args, extra = parser1.parse_known_args()
parser2 = argparse.ArgumentParser()
parser2.add_argument('--foo')
if extra:
args = parser2.parse_args(extra)
print(args)
运行
1815:~/mypy$ python stack41431025.py --foo 1 cmd1
Namespace(cmd='cmd1', foo='1')
1815:~/mypy$ python stack41431025.py cmd1 --foo 2
Namespace(foo='2')
1815:~/mypy$ python stack41431025.py --foo 1 cmd1 --foo 3
Namespace(foo='3')
我没有测试过这种想法在东西比较复杂,因此可能有一些是我没有想到的相互作用。但这是最接近我可以在任何地方发生的被标记的论点,而不会受到冲突的default
问题。
感谢您的详细解答Hpaulj让我测试它以适合我的代码 – Flippym
如果我理解正确,'argparse'不支持全局参数,我将不得不在每个子分析器中用'dest'来控制它们,right ? – Flippym
我已经添加了一个使用'parse_known_args'和第二个解析运行的例子。 – hpaulj