有没有办法在Argparser中设置没有前缀的选项?

3 投票
2 回答
1389 浏览
提问于 2025-04-16 08:08

我正在使用 Argparser 来处理我的命令行程序的参数。但随着时间的推移,我觉得这并不是个好主意。现在出现了问题。我想使用没有任何前缀字符的选项。就像 git commitsvn move 这样的命令。我查了一下,发现 Argparse 有一个 add_subparser() 方法。让我们来填充我们的 foo 程序:

parser = argparse.ArgumentParser(prog='foo', usage='%(prog)s [options]')

subparsers = parser.add_subparsers(help='sub-command help')
parser_a = subparsers.add_parser('add', help='a help')
parser_a.add_argument('-ap', '--add-project',
                    nargs='*',
                    action='store',
                    help="Add project")

parser_d = subparsers.add_parser('del', help='a help')
parser_d.add_argument('-dp', '--delete-project',
                    nargs='*',
                    action='store',
                    help="Delete project")

args = parser.parser_args()

现在让我们执行 foo 并带上选项,打印 args 的命名空间(我没有把完整的代码贴出来,你明白我的意思):

$ ./foo del
Namespace(delete_project=None)
$ ./foo add
Namespace(add_project=None)

如你所见,如果我执行选项 del,那么 add_project 就不会传递给变量 args。如果我在 main() 函数中有一个 "if 条件" 语句,比如:

def main(args):

   if args.delete_project:
      ...
   if args.add_project:
      ...

如果我执行 ./foo del,我会遇到一个 AttributeError 异常,提示命名空间中没有名为 add_project 的属性。此外,我也无法给选项 deladd 传递任何参数。我还把 prefix_chars 设置为空字符串,但这也没有用。

那我该怎么处理呢?argparse 能否像 git、svn 等那样创建选项,还是我应该自己写一个函数来处理所有参数呢?

2 个回答

0

编辑:显然,default 的默认值是 None,这意味着我们没有默认值,所以你需要使用 TrueFalse(这其实是正确的做法)。

当你把参数添加到解析器时,需要加上 default

parser_a.add_argument('-ap', '--add-project',
                    nargs = '*',
                    action = 'store_true',
                    default = False,
                    help = "Add project")

你可以在这里查看 add_argument 方法的文档 这里。(我知道 argparse 的文档排版不是特别方便,特别是对于那些在示例中没有提到的用法)

另外,正如 Tobu 在他的回答中提到的,未使用的子解析器不会被调用,所以你不能安全地检查它们的值,除非至少在 try: 块中保护你的代码。不过,实际上,除非你有更复杂的情况需要共享状态,否则你应该使用将 action 与子解析器关联的功能。

0

与其使用你的 if 语句,argparse 的文档推荐你可以这样做

parser_X.set_defaults(action=action_func)
args.action(args)

这样,add_action 就会关注 add_project,而 del_action 则会关注 del_project。

撰写回答