首页 > 解决方案 > 如何正确使用可选的 argparse 参数和子解析器

问题描述

我正在尝试编写一个小应用程序,它可以根据 argparse 中指定的参数执行多项操作。

我对必须始终指定的文件目录使用位置参数(soundfiledir),但之后我想根据我希望应用程序执行的内容指定参数。例如,-A 标志将运行一组特定的作业(python main.py [声音文件路径] -A)

parser = argparse.ArgumentParser()

parser.add_argument('soundfiledir', type=soundfiledir_format, help = "Specify soundfile directory") #positional argument. must always be provided.
parser.add_argument('-A', '--all', action = "store_true", help = "If this flag is specified, the program will transcribe all the sound files in the sound file directory (with timestamps), and will automatically concatenate files recorded close in time")

if args.all: 
does stuff

除此之外,我还使用子解析器。例如,可以使用一些选项(python main.py [soundfile path] fileconcatenator -a 15)指定名为 fileconcatenator (python main.py [soundfile path] fileconcatenator) 的子解析器

subparser = parser.add_subparsers(dest = 'command')

fileconcatenator_parser = subparser.add_parser('fileconcatenator', help = "Concatenates sound files together")
group1 = fileconcatenator_parser.add_mutually_exclusive_group(required=True)
group1.add_argument('-a','--autoconcat',type = positive_int,  nargs = "?", const = 3, default = None, \
    help="Concatenate audio files recorded close in time. By default any file recorded within 3mns of each other.")
group1.add_argument('-m', '--manconcat', type = list, default = [], \
    help = "Concatenate audio files specified as a list.")

fileconverter_parser = subparser.add_parser('fileconverter',help = "Converts files to 16kHz mono wav")
fileconverter_parser.add_argument('-f', '--filestoconvert', type = list, required=True, default = ["All"], \
    help = "Specify which files to convert.")

注意:您可能会注意到我将类型设置为 positive_int,这是用户指定的类型,使用

def positive_int(s):
    try:
        value = int(s)
        return int(s)
    except ValueError:
        raise argparse.ArgumentTypeError(f"Expected positive integer got {s!r}")
    if value <= 0:
        raise argparse.ArgumentTypeError(f"Expected positive integer got {s!r}")

总的来说,我的设置如下:

def main():

if args.all:
    
    do stuff

if args.autoconcat is None:
    pass
else:
   do stuff

问题是,当我运行python main.py [soundfile path] -A时,我得到AttributeError: 'Namespace' object has no attribute 'autoconcat'

该程序仍在运行(因为 if args.autoconcat 出现在 if args.all 块之后),但我想知道我做错了什么。

非常感谢任何帮助。如果您觉得不清楚,我会修改问题。

标签: pythonpython-3.xargparse

解决方案


Python argparse 文档的引用:

请注意, parse_args() 返回的对象将仅包含主解析器和命令行选择的子解析器(而不是任何其他子解析器)的属性。所以上例中,指定a命令时,只存在foo和bar属性,指定b命令时,只存在foo和baz属性。

这正是您的情况:您没有调用程序子命令fileconcatenator,因此该args对象将不包含该子命令的参数,例如 autoconcat。您必须首先检查调用了哪个子命令。这可以通过为所有子命令设置一个通用选项来完成,命令行用户无法修改该选项。它将为每个子命令单独设置,当子命令 a 被调用时,该参数的值为 a,而当子命令 b 被调用时,该参数的值为 b。这可以通过set_defaults像这样调用每个子解析器来实现:

fileconcatenator_parser = subparser.add_parser('fileconcatenator', help = "Concatenates sound files together")
fileconcatenator_parser.set_defaults(parser_name="fileconcatenator")
# adding some arguments here

fileconverter_parser = subparser.add_parser('fileconverter',help = "Converts files to 16kHz mono wav")
fileconverter_parser.set_defaults(parser_name="fileconverter")
#adding some arguments here

然后在 main 中,首先检查parser_name是 fileconverter 还是 fileconcatenator,然后根据调用的子命令检查参数。

def main():
    args = parser.parse_args()
    if args.parser_name == "fileconverter":
        # do something with args.filestoconvert
    elif args.parser_name == "fileconcatenator":
        if args.autoconcat is None:
             pass
        else:
             # do something

您可能必须调用set_defaults(parser_name="main")主解析器才能使其工作。


推荐阅读