Python argparse 位置参数和子命令 [英] Python argparse positional arguments and sub-commands

查看:28
本文介绍了Python argparse 位置参数和子命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 argparse 并尝试混合使用子命令和位置参数,但出现了以下问题.

I'm working with argparse and am trying to mix sub-commands and positional arguments, and the following issue came up.

此代码运行良好:

import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

parser.add_argument('positional')
subparsers.add_parser('subpositional')

parser.parse_args('subpositional positional'.split())

上面的代码将 args 解析为 Namespace(positional='positional'),但是当我将位置参数更改为具有 nargs='?'像这样:

The above code parses the args into Namespace(positional='positional'), however when I change the positional argument to have nargs='?' as such:

import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()

parser.add_argument('positional', nargs='?')
subparsers.add_parser('subpositional')

parser.parse_args('subpositional positional'.split())

它出错了:

usage: [-h] {subpositional} ... [positional]
: error: unrecognized arguments: positional

这是为什么?

推荐答案

起初我认为与 jcollado 相同,但事实是,如果后续(顶级)位置参数具有特定的 nargs (nargs = None, nargs = integer),然后它会按您的预期工作.当 nargs'?''*' 时,它会失败,有时当它是 '+' 时.所以,我深入研究了代码,想弄清楚发生了什么.

At first I thought the same as jcollado, but then there's the fact that, if the subsequent (top level) positional arguments have a specific nargs (nargs = None, nargs = integer), then it works as you expect. It fails when nargs is '?' or '*', and sometimes when it is '+'. So, I went down to the code, to figure out what is going on.

归结为参数被拆分以供使用的方式.为了弄清楚谁得到了什么,对 parse_args 的调用总结了一个字符串中的参数,如 'AA',在你的情况下 ('A'对于位置参数,'O' 为可选),并最终生成一个正则表达式模式以与该摘要字符串匹配,具体取决于您通过 添加到解析器的操作.add_argument.add_subparsers 方法.

It boils down to the way the arguments are split to be consumed. To figure out who gets what, the call to parse_args summarizes the arguments in a string like 'AA', in your case ('A' for positional arguments, 'O' for optional), and ends up producing a regex pattern to be matched with that summary string, depending on the actions you've added to the parser through the .add_argument and .add_subparsers methods.

在每种情况下,例如,参数字符串最终都是 'AA'.改变的是要匹配的模式(你可以在 argparse.py 中的 _get_nargs_pattern 下看到可能的模式.对于 subpositional,它最终是 _get_nargs_patterncode>'(-*A[-AO]*)',这意味着允许一个参数后跟任意数量的选项或参数.对于位置,这取决于传递给 nargs 的值:

In every case, for you example, the argument string ends up being 'AA'. What changes is the pattern to be matched (you can see the possible patterns under _get_nargs_pattern in argparse.py. For subpositional it ends up being '(-*A[-AO]*)', which means allow one argument followed by any number of options or arguments. For positional, it depends on the value passed to nargs:

  • => '(-*A-*)'
  • 3 => '(-*A-*A-*A-*)'(每个预期参数一个 '-*A')
  • '?' => '(-*A?-*)'
  • '*' => '(-*[A-]*)'
  • '+' => '(-*A[A-]*)'
  • None => '(-*A-*)'
  • 3 => '(-*A-*A-*A-*)' (one '-*A' per expected argument)
  • '?' => '(-*A?-*)'
  • '*' => '(-*[A-]*)'
  • '+' => '(-*A[A-]*)'

附加这些模式,对于 nargs=None(您的工作示例),您最终会得到 '(-*A[-AO]*)(-*A-*)',匹配两组['A', 'A'].这样,subpositional 将只解析 subpositional(你想要的),而 positional 将匹配它的动作.

Those patterns are appended and, for nargs=None (your working example), you end up with '(-*A[-AO]*)(-*A-*)', which matches two groups ['A', 'A']. This way, subpositional will parse only subpositional (what you wanted), while positional will match its action.

但是,对于 nargs='?',您最终会得到 '(-*A[-AO]*)(-*A?-*)'.第二组完全由 optional 模式组成,并且 * 是贪婪的,这意味着第一组对字符串中的所有内容进行 glob,最终识别出这两组 ['AA', ''].这意味着 subpositional 获得两个参数,当然最终会窒息.

For nargs='?', though, you end up with '(-*A[-AO]*)(-*A?-*)'. The second group is comprised entirely of optional patterns, and * being greedy, that means the first group globs everything in the string, ending up recognizing the two groups ['AA', '']. This means subpositional gets two arguments, and ends up choking, of course.

有趣的是,nargs='+' 的模式是 '(-*A[-AO]*)(-*A[A-]*)'只要你只传递一个参数.说 subpositional a,因为您需要在第二组中至少有一个位置参数.同样,由于第一组是贪婪的,传递 subpositional a b c d 会得到 ['AAAA', 'A'],这不是你想要的.

Funny enough, the pattern for nargs='+' is '(-*A[-AO]*)(-*A[A-]*)', which works as long as you only pass one argument. Say subpositional a, as you require at least one positional argument in the second group. Again, as the first group is greedy, passing subpositional a b c d gets you ['AAAA', 'A'], which is not what you wanted.

简而言之:一团糟.我想这应该被认为是一个错误,但不确定如果模式变成非贪婪模式会产生什么影响......

In brief: a mess. I guess this should be considered a bug, but not sure what the impact would be if the patterns are turned into non-greedy ones...

这篇关于Python argparse 位置参数和子命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆