可以Python的argparse permute参数顺序像gnu getopt? [英] Can Python's argparse permute argument order like gnu getopt?

查看:185
本文介绍了可以Python的argparse permute参数顺序像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似乎不支持(或者甚至提到)置换选项。



有很多SO问题与arg / opt命令相关,但没有人能回答这个问题:argparse be



该用例是一个原型命令行签名,如GNU sort:

  sort [opts] [files] 

选项和文件被排列,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
用法:ipython [-h] [-z] [files [files ...]]

我试过:




  • p.parse_known_args - 不抱怨,但实际上没有置换,

  • p.add_argument('files',nargs = argparse.REMAINDER) - option - z包含在文件中,除非在位置参数之前

  • p.add_argument('files',nargs ='*',action ='append');



我想实现一个接近上面GNU排序原型的东西。我不感兴趣的可以为每个文件指定的标志(例如,-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)
如果项目为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_pa​​rse(argv = None):
opts = parser.parse_args(argv)
optargs = opts.args_tail
when optargs:
opts = parser.parse_args(optargs,opts)
optargs = opts.args_tail
return opts

print(interleaved_pa​​rse(' - z bar foo'.split()))
print(interleaved_pa​​rse('bar foo -z'.split()))
print(interleaved_pa​​rse('bar -z foo'.split()))
print(interleaved_pa​​rse(' - va -zv b -zc -vz d -v'.split()))

输出:

 命名空间(args_tail = [],files = ['bar','foo'],v = None,z = True)
命名空间'],v = None,z = True)
命名空间(args_tail = [],files = ['bar','foo'],v = None,z = True)
命名空间[],files = ['a','b','c','d'],v = 4,z = True)

注意:不要尝试使用其他非标志参数(除了单个 nargs ='*'参数和 args_tail 参数)。解析器不会知道之前对 parse_args 的调用,因此它将为这些非标志参数存储错误的值。作为解决方法,您可以在使用 interleaved_pa​​rse 后手动解析 nargs ='*' b $ b

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.

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?

The use case is a prototypical command line signature like GNU sort:

sort [opts] [files]

in which 1) options and files are permuted, and 2) the file list may contain zero or more arguments.

For example:

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 ...]]

I've tried:

  • p.parse_known_args -- doesn't complain, but doesn't actually permute either and it doesn't balk about arguments that look like invalid options (e.g., --bogus or -b above).
  • p.add_argument('files',nargs=argparse.REMAINDER) -- option -z is included in files unless before positional args
  • p.add_argument('files',nargs='*',action='append');

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()))

Output:

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)

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 permute参数顺序像gnu getopt?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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