如何正确使用可选的 argparse 参数和子解析器

How to use optional argparse argument and subparsers properly

我正在尝试编写一个小应用程序,它可以根据 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

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

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' 对象没有属性 'autoconcat'

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

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

引自 Python argparse docs:

Note that the object returned by parse_args() will only contain attributes for the main parser and the subparser that was selected by the command line (and not any other subparsers). So in the example above, when the a command is specified, only the foo and bar attributes are present, and when the b command is specified, only the foo and baz attributes are present.

这正是您的情况:您没有调用程序子命令 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") 让它发挥作用。