Python 的 argparse 可以像 gnu getopt 一样置换参数顺序吗? [英] Can Python's argparse permute argument order like gnu getopt?
问题描述
GNU getopt 和使用它的命令行工具允许选项和参数交错,称为置换选项(参见 http://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html#Using-Getopt).Perl 的 Getopt::Long 模块也支持这个(使用 qw(:config gnu_getopt)).argparse 似乎不支持(甚至提到)置换选项.
GNU getopt, and command line tools that use it, allow options and arguments to be interleaved, known as permuting options (see http://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html#Using-Getopt). Perl's Getopt::Long module also supports this (with qw(:config gnu_getopt)). argparse seems to not support (or even mention) permuting options.
有很多与 arg/opt 顺序相关的 SO 问题,但似乎没有一个能回答这个问题:可以让 argparse 像 getopt 一样置换参数顺序吗?
There are many SO questions related to arg/opt order, but none seem answer this question: Can argparse be made to permute argument order like getopt?
用例是一个原型命令行签名,如 GNU sort:
The use case is a prototypical command line signature like GNU sort:
sort [opts] [files]
其中 1) 选项和文件被置换,以及 2) 文件列表可能包含零个或多个参数.
in which 1) options and files are permuted, and 2) the file list may contain zero or more arguments.
例如:
import argparse
p = argparse.ArgumentParser();
p.add_argument('files',nargs='*',default=['-']);
p.add_argument('-z',action='store_true')
p.parse_args(['-z','bar','foo']) # ok
p.parse_args(['bar','foo','-z']) # ok
p.parse_args(['bar','-z','foo']) # not okay
usage: ipython [-h] [-z] [files [files ...]]
我试过了:
- p.parse_known_args -- 不会抱怨,但实际上也不会进行置换,并且不会回避看起来像无效选项的参数(例如,上面的 --bogus 或 -b).
- p.add_argument('files',nargs=argparse.REMAINDER) -- 选项 -z 包含在文件中,除非在位置参数之前
- p.add_argument('files',nargs='*',action='append');
我想实现一些接近于上面的 GNU 排序原型的东西.我对可以为每个文件指定的标志不感兴趣(例如,-f file1 -f file2).
I want to implement something close to the GNU sort prototype above. I am not interested in a flag that can be specified for each file (e.g., -f file1 -f file2).
推荐答案
这是一个快速的解决方案,它一次解码一对参数列表(选项、位置参数).
Here's a quick solution which decodes the argument list one (options, positional arguments) pair at a time.
import argparse
class ExtendAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
items = getattr(namespace, self.dest, None)
if items is None:
items = []
items.extend(values)
setattr(namespace, self.dest, items)
parser = argparse.ArgumentParser()
parser.add_argument('files', nargs='*', action=ExtendAction)
parser.add_argument('-z', action='store_true')
parser.add_argument('-v', action='count')
parser.add_argument('args_tail', nargs=argparse.REMAINDER)
def interleaved_parse(argv=None):
opts = parser.parse_args(argv)
optargs = opts.args_tail
while optargs:
opts = parser.parse_args(optargs, opts)
optargs = opts.args_tail
return opts
print(interleaved_parse('-z bar foo'.split()))
print(interleaved_parse('bar foo -z'.split()))
print(interleaved_parse('bar -z foo'.split()))
print(interleaved_parse('-v a -zv b -z c -vz d -v'.split()))
输出:
Namespace(args_tail=[], files=['bar', 'foo'], v=None, z=True)
Namespace(args_tail=[], files=['bar', 'foo'], v=None, z=True)
Namespace(args_tail=[], files=['bar', 'foo'], v=None, z=True)
Namespace(args_tail=[], files=['a', 'b', 'c', 'd'], v=4, z=True)
注意:不要尝试将它与其他非标志参数一起使用(除了单个 nargs='*'
参数和 args_tail
参数).解析器不会知道之前对 parse_args
的调用,因此它会为这些非标志参数存储错误的值.作为一种解决方法,您可以在使用 interleaved_parse
后手动解析 nargs='*'
参数.
Note: Don't try to use this with other non-flag arguments (besides a single nargs='*'
argument and the args_tail
argument). The parser won't know about previous invocations of parse_args
so it will store the wrong value for these non-flag arguments. As a workaround, you can parse the nargs='*'
argument manually after using interleaved_parse
.
这篇关于Python 的 argparse 可以像 gnu getopt 一样置换参数顺序吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!