【问题标题】:Create parser with subcommands in argparse, customize positional argument(s)在 argparse 中使用子命令创建解析器,自定义位置参数
【发布时间】:2015-07-11 23:12:15
【问题描述】:

我对这个模块很陌生,所以请多多包涵。我有以下代码:

reader.py

import argparse

parent_parser = argparse.ArgumentParser(description="Read text files.")
parent_parser.add_argument('filename', help='TXT file', type=file, nargs='+')
parent_parser.add_argument('--verbose', '-v', action='store_true', 
        help="Verbosity on")

child_parser = parent_parser.add_subparsers(title="subcommand",
        help="Subcommand help")
new_file_command = child_parser.add_parser('new', help="New text file")
edit_file_command = child_parser.add_parser('edit', help="Edit existing text file")

args = parent_parser.parse_args()

我想要实现的可能不是解析器和 unix 命令行实用程序工作方式的标准方式。如果这是真的,请纠正我,因为我想要标准化的应用程序。

这就是我想要实现的目标:

  • 如果您使用这样的位置参数运行裸脚本:python reader.py some.txt 我希望能够解析它并将其传递给读取文本文件的函数,当然我想接受可选参数verbose 也一样
  • 如果你运行子命令'new' (new_file_command),我不想有位置参数filename,而是我想传递一个字符串并创建新的文本文件,如下所示:python reader.py new another.txt
  • 如果你运行子命令 'edit' (edit_file_command) 我想在路径中传递现有文件并检查它(就像你在 add_argument 中使用 type=int)然后可能将它传递给打开编辑器的函数,像这样的东西:python reader.py edit some.txt

同样,我不确定这是否是命令行应用程序/脚本的行为方式。我阅读了文档并查看了示例,但我仍然不清楚子解析器是如何工作的。我尝试查看 Click 模块,但在我看来这更复杂。

任何帮助表示赞赏。谢谢!

【问题讨论】:

    标签: python command-line-arguments argparse


    【解决方案1】:

    所以三个示例调用是:

    python reader.py some.txt 
    python reader.py new another.txt
    python reader.py edit some.txt
    

    处理这些问题的最简单方法是使用一个“可选”位置和一个必需的位置。

    parser = ArgumentParser...
    parser.add_argument('-v','--verbose', ...)
    parser.add_argument('cmd', nargs='?', default='open', choices=['open','edit','new'])
    parser.add_argument('filename')
    

    对于您的 3 个样本,它应该产生如下内容:

    namespace(cmd='open', filename='some.txt')
    namespace(cmd='new', filename='another.txt')
    namespace(cmd='edit', filename='some.txt')
    

    cmd 是一个可选的位置参数。如果缺少,则将一个字符串分配给filename,而cmd 将得到它的default。这样做比尝试将subparsers 设为可选更容易。


    至于你当前的解析器:

    parent_parser = argparse.ArgumentParser(description="Read text files.")
    parent_parser.add_argument('filename', help='TXT file', type=file, nargs='+')
    

    我不建议使用type=file。最好使用FileType 或默认字符串(让您稍后在with context 中打开文件)。

    至于nargs='+',你真的要把1 or more字符串分配给filename吗?或者您是否在考虑“?”,即0 or 1,即使其成为可选?

    parent_parser.add_argument('--verbose', '-v', action='store_true', 
            help="Verbosity on")
    
    child_parser = parent_parser.add_subparsers(title="subcommand",
            help="Subcommand help")
    new_file_command = child_parser.add_parser('new', help="New text file")
    edit_file_command = child_parser.add_parser('edit', help="Edit existing text file")
    

    将这个接受可变数量值的filename 位置与子解析器参数(预期newedit 的位置)混合可能会出现问题。

    我希望'python reader.py some.txt' 反对缺少子解析器命令。 'python reader.py new another.txt' 将尝试将new 分配给filename,并将another.txt 分配给子解析器,并引发错误。

    最好在所有 3 种情况下都使用 subparsers 命令:

    parent_parser = argparse.ArgumentParser(description="Read text files.")
    parent_parser.add_argument('--verbose', '-v', action='store_true', 
            help="Verbosity on")
    child_parser = parent_parser.add_subparsers(title="subcommand",
            help="Subcommand help", dest='cmd')
    open_file_command = child_parser.add_parser('open', help="Open text file")
    open_file_command.add_argument('filename', help='TXT file')
    new_file_command = child_parser.add_parser('new', help="New text file")
    new_file_command.add_argument('filename', help='TXT file')
    edit_file_command = child_parser.add_parser('edit', help="Edit existing text file")
    edit_file_command.add_argument('filename', help='TXT file')
    

    每个命令,“打开”、“新建”、“编辑”,都需要一个“文件名”。

    试图避免使用open 命令会带来更多的困难。

    (最新的 argparse 中有一个错误/功能使子解析器成为可选的,但您不应该在不真正了解问题的情况下利用它。)


    与:

    parser = argparse.ArgumentParser()
    parser.add_argument('-v', '--verbose') 
    parser.add_argument('cmd', nargs='?', default='open', 
        choices=['open', 'edit', 'new']) 
    parser.add_argument('filename', nargs='+') 
    

    我希望reader.py new customstring 给予

    namespace(cmd='new', filename=[customstring])
    

    可以用作:

    if args.cmd=='new':
    with open(args.filename[0] + '.txt', 'w') as f:
         # do something with the newly created file
    

    openedit 将使用不同的 open 模式。


    请注意,在 Py3 中,subparsers 不是必需的。也就是说,如果未提供其中一个子命令,则不会引发错误。这是早期版本的无意更改。

    Argparse with required subparser

    【讨论】:

    • 您好,感谢您的帮助。不过,我还有最后一个问题。我仍然想知道如何自定义位置参数。假设我有以下代码: parser = argparse.ArgumentParser() parser.add_argument('-v', '--verbose') parser.add_argument('cmd', nargs='?', default='open', options =['open', 'edit', 'new']) parser.add_argument('filename', nargs='+') 如果我想为命令new 自定义位置参数怎么办?我不需要/想要传递显式文件名,而只是像some 这样的字符串,然后它会创建文件some.txt。我该怎么做呢?谢谢
    • 您可以创建自定义typeAction。但通常在解析后进行这种更改会更简单。特别是如果您没有对“某些”进行任何错误检查。
    • 您好,我仍在浏览文档并试图弄清楚这一点,但我无法在网上找到更多示例。你能告诉我一个 sn-p 在解析后你将如何实现它吗?因为如果我执行reader.py new customstring,它会对现有文件名进行错误检查,所以它不会让我做任何事情。
    猜你喜欢
    • 2013-09-13
    • 1970-01-01
    • 2012-01-29
    • 1970-01-01
    • 2013-08-30
    • 2020-11-10
    • 1970-01-01
    • 2019-09-23
    相关资源
    最近更新 更多