2012-03-02 34 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='*'參數。

相關問題