2012-03-02 84 views
9

GNU getopt和使用它的命令行工具允许选项和参数交错,称为排列选项(请参阅http://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html#Using-Getopt)。 Perl的Getopt :: Long模块也支持这个(使用qw(:config gnu_getopt))。 argparse似乎不支持(甚至不提)排列选项。Python的argparse排列顺序可以像gnu getopt一样吗?

有很多SO问题与arg/opt顺序有关,但似乎没有人回答这个问题:是否可以使用getopt来排列参数顺序的argparse?

用例是原型命令行签名等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 - 不抱怨,但实际上并没有任何置换,并没有放水有关参数看起来像无效的选项(例如, - 博格斯或上面的-b)。
  • p.add_argument( '文件',NARGS = argparse.REMAINDER) - 选项-z被包括在文件,除非前位置ARGS
  • p.add_argument( '文件',NARGS = '*',动作=”附加');

我想实现一些接近上面的GNU排序原型。我对可以为每个文件指定的标志不感兴趣(例如-f file1 -f file2)。

回答

3

我在argparse文档中没有看到明确的说明它可以或不可以排列。根据你自己的观察结果,排列失败的地方,以及下面的文档引用,我将得出结论,它不能完成。

  1. 不过已经有了明确命名为“getopt”模块:

    getopt模块是命令行选项,其API 被设计成熟悉的C getopt()功能的用户解析器。用户 谁不熟悉C getopt()函数或谁想要 写少量代码并获得更好的帮助和错误消息应该考虑 使用​​模块来代替。

  2. 即使是默认的getopt不置换,有一个名为gnu_getopt()一个更加明确的方法:

    此函数类似于getopt(),除了GNU风格的扫描模式 默认情况下使用。这意味着选项和非选项参数 可能会混在一起。

  3. 在getopt的文档,上述参考argparse是进一步放大通过包括以下的:

    注意,等效的命令行界面可以与 更少的代码和更多的信息来产生通过使用 ​​模块帮助和错误消息:

Agai n,没有什么明确的,但对我来说,getopt和argparse之间的区别在于赞成/主张argparse的文档。

下面是一个使用gnu_getop()其中一个例子satifies您-z [file [file]]测试:

>>> args = 'file1 -z file2'.split() 
>>> args 
['file1', '-z', 'file2'] 
>>> opts, args = getopt.gnu_getopt(args, 'z') 
>>> opts 
[('-z', '')] 
>>> args 
['file1', 'file2'] 

编辑:进入置换自己,用argparse

通过 “置换” 的定义启发在“使用的Getopt '你链接到的页面,

默认情况下是在扫描它时对argv的内容进行置换所以最终所有的非选项都在最后。

如何在将参数传递到parse_args()之前进行排序?

import argparse 

p = argparse.ArgumentParser(); 
p.add_argument('files',nargs='*',default=['-']); 
p.add_argument('-z',action='store_true') 

滚动自己:

import re 

def permute(s, opts_ptn='-[abc]'): 
    """Returns a permuted form of arg string s using a regular expression.""" 
    opts = re.findall(opts_ptn, s) 
    args = re.sub(opts_ptn, '', s) 
    return '{} {}'.format(' '.join(opts), args).strip() 

>>> p.parse_args(permute('bar -z foo', '-[z]').split()) 
Namespace(files=['bar', 'foo'], z=True) 

利用的getopt:

import getopt 

def permute(s, opts_ptn='abc'): 
    """Returns a permuted form of arg string s using `gnu_getop()'.""" 
    opts, args = getopt.gnu_getopt(s.split(), opts_ptn) 
    opts = ' '.join([''.join(x) for x in opts]) 
    args = ' '.join(args) 
    return '{} {}'.format(opts, args).strip() 

>>> p.parse_args(permute('bar -z foo', 'z').split()) 
Namespace(files=['bar', 'foo'], z=True) 
4

这里有一个快速的解决方案,其解码参数列表中的一个(选项,定位参数)对在同一时间。

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='*'参数。

相关问题