【发布时间】:2019-01-13 00:14:38
【问题描述】:
我正在用 Python 开发一个命令行工具,它的功能被分解成许多子命令,基本上每个子命令都作为参数输入和输出文件。棘手的部分是每个命令需要不同数量的参数(有些不需要输出文件,有些需要多个输入文件等)。
理想情况下,接口将被称为:
./test.py ncinfo inputfile
然后,解析器会意识到ncinfo 命令需要一个参数(如果这不适合输入命令,它会抱怨),然后它会调用函数:
ncinfo(inputfile)
这才是真正的工作。
当命令需要更多选项时,例如
./test.py timmean inputfile outputfile
解析器会意识到这一点,检查是否确实给出了两个参数,然后它会调用:
timmean(inputfile, outputfile)
此方案理想地推广到任意列表的 1 参数命令、2 参数命令等。
但是,我正在努力使用 Python argparse 来实现这种行为。这是我目前所拥有的:
#! /home/navarro/SOFTWARE/anadonda3/bin/python
import argparse
# create the top-level parser
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
# create the parser for the "ncinfo" command
parser_1 = subparsers.add_parser('ncinfo', help='prints out basic netCDF strcuture')
parser_1.add_argument('filein', help='the input file')
# create the parser for the "timmean" command
parser_2 = subparsers.add_parser('timmean', help='calculates temporal mean and stores it in output file')
parser_2.add_argument('filein', help='the input file')
parser_2.add_argument('fileout', help='the output file')
# parse the argument lists
parser.parse_args()
print(parser.filein)
print(parser.fileout)
但这并没有按预期工作。首先,当我调用不带参数的脚本时,我没有收到错误消息告诉我有哪些选项。其次,当我尝试运行程序以使用ncinfo 时,出现错误
./test.py ncinfo testfile
Traceback (most recent call last):
File "./test.py", line 21, in <module>
print(parser.filein)
AttributeError: 'ArgumentParser' object has no attribute 'filein'
我做错了什么导致我无法实现预期的行为?在这种情况下使用subparsers 是否合理?
奖励点:有没有办法概括命令的定义,这样我就不需要手动添加每个命令?例如,将所有 1 参数命令分组到一个列表中,然后在循环中定义解析器。这听起来很合理,但我不知道这是否可能。否则,随着工具数量的增加,解析器本身将变得难以维护。
【问题讨论】:
-
您可以执行
for name in one_arg_commands:之类的操作,然后为此创建每个子解析器,然后创建for name in two_arg_commands:,等等。 -
通常你会从
argparse和-h或--help得到help。没有参数时没有默认行为。在调试期间,我喜欢print(args)来清楚地了解它设置了哪些属性。您可能还想将dest添加到add_subparsers以查看正在使用的子解析器。并设置args=parser.parse_args()。解析创建一个args命名空间;它不会修改parser。 -
我是个菜鸟,所以我可以相信默认设置是有充分理由的……但我不明白。当命令行不满足任何预期配置时,让程序继续运行似乎是个坏主意。事实上,@simleo 响应中的示例在没有给出参数时会崩溃(引发异常)。我希望解析器的行为就像使用了
-h标志一样。实际上,这是不使用子命令时的行为。我很想相信这是一个错误......