# 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行为?
答案 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)
会将根解析器参数复制到一个新的子解析器中,包括子解析器本身。这导致无法解析的无限解析循环。