Subparser argparse“错误:参数太少”

时间:2018-11-05 16:15:52

标签: python python-2.7 argparse

# bird.py
from argparse import ArgumentParser, SUPPRESS

parser = ArgumentParser(argument_default=SUPPRESS)
parser.add_argument('--dead', action='store_true')
subparsers = parser.add_subparsers()
subparser = subparsers.add_parser('parrot', parents=[parser], add_help=False)
subparser.add_argument('--volts', type=int)
args = parser.parse_args()
print(args)

上面的脚本bird.py在Python 3上可以正常工作。但是在Python 2.7上,它不会解析参数:

$ python3 bird.py parrot --volts 4000000
Namespace(volts=4000000)
$ python2 bird.py parrot --volts 4000000
usage: bird.py parrot [-h] [--dead] [--volts VOLTS] {parrot} ...
bird.py parrot: error: too few arguments

据我所知,代码中没有使用任何仅py3功能。为什么不一样?如何更新此代码,以便CLI也可以支持Python 2.7,不以任何方式修改其Python 3行为

2 个答案:

答案 0 :(得分:1)

parents复制的副本数量超出您的期望。 parents试图复制父母的子解析器,最终试图使subparser成为其自身的子解析器。在Python 3上,子解析器默认为可选,因此parrot没有得到自己的parrot的事实不是错误。在Python 2上,需要使用子解析器,因此parrot需要自己的parrot并抱怨无法获取它。 (考虑到您在尝试将其用作父级时正在通过添加子解析器来修改父级解析器,因此如果损坏甚至更多,我也不会感到惊讶。)

与其尝试使用parser作为其自身的子解析器的父级,不如创建一个单独的父解析器,并将其用作顶级解析器和parrot子解析器的父级:

from argparse import ArgumentParser

shared = ArgumentParser(add_help=False)
shared.add_argument('--dead', action='store_true')

parser = ArgumentParser(parents=[shared])
subparsers = parser.add_subparsers()
subparser = subparsers.add_parser('parrot', parents=[shared])
subparser.add_argument('--volts', type=int)
args = parser.parse_args()
print(args)

结果:

$ python2 bird.py parrot --volts 4000000
Namespace(dead=False, volts=4000000)
$ python3.6 bird.py parrot --volts 4000000
Namespace(dead=False, volts=4000000)

但是,还有更多的问题,因为您要向父母和孩子都添加--dead选项,并且他们正试图在同一位置写入。该孩子似乎具有优先权:

$ python bird.py --dead parrot
Namespace(dead=False, volts=None)
$ python bird.py parrot --dead
Namespace(dead=True, volts=None)

如果顶级解析器和子解析器具有不同的--dead值,或者它们具有dest以外的动作,则为store_true选项提供合理性可能是有意义的,但是用现在的方式,这没有多大意义。如果您想要dest的其他值,我认为您不能为此使用parents机制。

答案 1 :(得分:0)

此错误来自parents调用中的subparsers.add_parser()参数。

# bird.py
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('--dead', action='store_true')
subparsers = parser.add_subparsers()
subparser = subparsers.add_parser('parrot', add_help=False)
subparser.add_argument('--volts', type=int)
args = parser.parse_args()
print(args)

然后

$ python scratch.py parrot --volts 1000
Namespace(dead=False, volts=1000)

原因是使用subparsers.add_parser()创建了一个新的解析器,调用了调用ArgumentParser的构造函数:

class ArgumentParser(_AttributeHolder, _ActionsContainer):
    """Object for parsing command line strings into Python objects.

    Keyword Arguments:
        - [...]
        - parents -- Parsers whose arguments should be copied into this one
    """

调用subparsers.add_parser('parrot', parents=[parser], add_help=False)会将根解析器参数复制到一个新的子解析器中,包括子解析器本身。这导致无法解析的无限解析循环。