2016-12-06 41 views
4

例如,使用GNU ls可以使用--color[=WHEN]選項控制着色。現在在這種情況下,等號是至關重要的,因爲ls必須區分--color的可選參數和位置參數(這是要列出的文件)。即ls --color列出帶顏色的文件,與ls --color=always相同,但ls --color always將列出文件always(以及顏色)。在argparse中使用GNU風格的長選項(不會混淆可選參數與位置)

現在從我看到的​​似乎接受使用--longopt <argument>語法的長期選項的參數,這將導致無法使參數可選。也就是說,如果我嘗試實施myls具有相同的行爲GNU ls(這只是一個例子),我會遇到問題,因爲現在myls --color always的含義一樣myls --color=always(而不是要求--color不用爭論和always的位置參數)。

我知道我可以通過使用myls --color -- always來規避這種情況,但沒有辦法在沒有該解決方法的情況下使其工作?這是告訴​​,--color的參數必須以--color[=WHEN]語法提供。

請注意,我不希望依賴--color選件的有效參數數量有限的事實。這裏有一個例子我已經試過了沒有正常工作:

import argparse 

parser = argparse.ArgumentParser() 

parser.add_argument("--foo", 
        action="store", 
        nargs="?") 
parser.add_argument("frob", 
        action="store", 
        nargs=argparse.REMAINDER) 

print(parser.parse_args(["alpha", "beta"])) 
print(parser.parse_args(["--foo", "alpha", "beta"])) 
print(parser.parse_args(["--foo=bar", "alpha", "beta"])) 

隨着輸出:

Namespace(foo=None, frob=['alpha', 'beta']) 
Namespace(foo='alpha', frob=['beta']) 
Namespace(foo='bar', frob=['alpha', 'beta']) 

注意到第二哪裏alpha被解讀爲參數--foo。我想:

Namespace(foo=None, frob=['alpha', 'beta']) 
Namespace(foo=None, frob=['alpha', 'beta']) 
Namespace(foo='bar', frob=['alpha', 'beta']) 
+0

是否可以通過添加兩個參數來解決?一個是「--color」,另一個是「--color = always」。我現在沒有可用的終端來測試。 –

+0

我已經制定了一個需要對'argparse.py'進行小手術的補丁。 – hpaulj

回答

2

您可能已經嘗試了?可選其次需要位置:

p=argparse.ArgumentParser() 
p.add_argument('--foo', nargs='?',default='one', const='two') 
p.add_argument('bar') 

其失敗

In [7]: p.parse_args('--foo 1'.split()) 
usage: ipython3 [-h] [--foo [FOO]] bar 
ipython3: error: the following arguments are required: bar 

--foo消耗1,不爲bar留下任何東西。

http://bugs.python.org/issue9338討論了這個問題。 nargs='?'是貪婪的,消耗一個參數,即使下面的位置需要一個。但是建議的補丁很複雜,所以我不能很快將它應用到解析器並測試你的情況。

定義一個可以與--foo==value一起使用但不消耗value--foo value的Action的想法很有趣,但我不知道需要實現什麼。當然,它不適用於當前的解析器。我不得不回顧一下它如何處理這個顯式的=

============================

通過改變parse_args深深嵌套函數,

def consume_optional(....): 
     .... 
       # error if a double-dash option did not use the 
       # explicit argument 
       else: 
        msg = _('ignored explicit argument %r') 
        #raise ArgumentError(action, msg % explicit_arg) 
        # change for stack40989413 
        print('Warn ',msg) 
        stop = start_index + 1 
        args = [explicit_arg] 
        action.nargs=None 
        action_tuples.append((action, args, option_string)) 
        break 

,並添加自定義Action類:

class MyAction(myparse._StoreConstAction): 
    # requies change in consume_optional 
    def __call__(self, parser, namespace, values, option_string=None): 
     if values: 
      setattr(namespace, self.dest, values) 
     else: 
      setattr(namespace, self.dest, self.const) 

我可以得到所需的行爲:

p = myparse.ArgumentParser() 
p.add_argument('--foo', action=MyAction, const='C', default='D') 
p.add_argument('bar') 

基本上我正在修改store_const以保存=explicit_arg如果存在。

我不打算提議這是一個正式的補丁,但我會歡迎反饋,如果它是有用的。使用風險自負。 :)

-1

也許nargs會有所幫助。

>>> parser = argparse.ArgumentParser() 
>>> parser.add_argument('--color', nargs='?', const='c', default='d') 
>>> parser.parse_args(['XX', '--color', 'always']) 
Namespace(bar='XX', color='always') 
>>> parser.parse_args(['XX', '--color']) 
Namespace(bar='XX', color='c') 
>>> parser.parse_args([]) 
Namespace(bar='d', color='d') 

與NARGS,你會得到不同的指定參數和你就會知道輸入的類型是什麼。

順便說一句,我認爲--color選項可以使用action='store_true'

parser.add_argument('--color', action='store_true') 
+0

這不是問題所在。問題是'--foo always'應該被解釋爲'--foo'沒有可選參數,'always'應該被解釋爲位置參數的一部分。我想要使​​用'--foo'(不帶參數)或'--foo = always'。 – skyking

+0

恐怕你錯過了我的觀點(我也更新了這個問題)。問題是'--color always'應該**不被接受爲'--color = always'的意思。 – skyking

2

顯然這是不可能的。 GNU getopt()支持此行爲(man getopt,man 3 getopt)。 man getopt說:

如果[長]選項有一個可選參數,它必須在長選項名稱後直接寫入,由「=」分開,如果存在的話

Python的getopt模塊,然而,很明顯,它不支持:

不支持可選參數[in long options]。

對於​​我沒有在手冊中找到任何具體的參考,但如果它支持它,我會感到驚訝。事實上,我很驚訝GNU getopt支持它,並且ls按照您描述的方式工作。用戶界面應該很簡單,這種行爲遠非如此簡單。

+0

不幸的是,我很害怕這是正確的答案(除非有一個聰明/愚蠢/醜陋的解決方法)... – skyking

1

這裏有一個解決方法:

#!/usr/bin/python 

import argparse 

parser = argparse.ArgumentParser() 
parser.add_argument("files", nargs="*", help="List of files", type=str) 
parser.add_argument('--color', dest='color', action='store_true') 
parser.add_argument('--color=ALWAYS', dest='color_always', action='store_true') 

args = parser.parse_args() 
print args 

結果:

[~]$ ./test.py xyz --color 
Namespace(color=True, color_always=False, files=['xyz']) 
[~]$ ./test.py xyz --color=ALWAYS 
Namespace(color=False, color_always=True, files=['xyz']) 
+0

在這個特定的例子,將工作,但它是不可行的,如果它不是有限的有效參數。舉個例子,如果一個long選項有一個可選的路徑參數。 – skyking

+0

是的,我想不出如何做到這一點。 – VBB