python - Python 的 argparse 可以像 gnu getopt 一样置换参数顺序吗?

标签 python command-line command-line-arguments argparse 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 似乎不支持(甚至不提及)置换选项。

有很多与 arg/opt 顺序相关的 SO 问题,但似乎没有一个能回答这个问题:Can argparse be made to permute argument order like getopt?

用例是一个原型(prototype)命令行签名,如 GNU 排序:

sort [opts] [files]

其中 1) 选项和文件被置换,并且 2) 文件列表可以包含零个或多个参数。

例如:

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 排序原型(prototype)的东西。我对可以为每个文件指定的标志不感兴趣(例如,-f file1 -f file2)。

最佳答案

这是一个快速的解决方案,一次解码一个(选项,位置参数)对参数列表。

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_pa​​rse 后手动解析 nargs='*' 参数。

关于python - Python 的 argparse 可以像 gnu getopt 一样置换参数顺序吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9537510/

相关文章:

c++ - 提升程序选项选择

python - Pytest 在使用预定义参数 vai argparse 运行测试时抛出参数错误

python - 如何根据另一个行字符串重命名行字符串?

python - Word2Vec:使用 Gensim 上传预先训练的 word2vec 文件时收到错误

java - 通过使用文件重定向为其提供输入来运行 Java 程序

linux - Netbeans 7.1 内置终端命令

java - 为什么程序没有继续进行

python - 将 pandas MultiIndex 级别更改为 '+1'

python - 在涉及 Cython 的 setup.py 中,如果 install_requires,那么如何从库中导入一些东西?

Powershell cat 命令 - 为什么输出文件大小远大于输入文件大小的总和?