2014-10-09 116 views
1

是否可以創建一組相關且可重複的可選參數?Argparse,處理可重複的項目集

比方說,我有三個參數-a,-b,-c形成一個集合, -a是必需的,但-b和-c是可選的。 (已更新)

我希望能夠指定多組這些。

Script.py -a 1 -b 2 -c 3 -a 4 -c 6 -a 7 -b 8 -a 10 

如下

[ 
    {"a":1, "b":2, "c":3}, 
    {"a":4, "c":6}, 
    {"a":7, "b":8}, 
    {"a":10} 
] 
+0

你將如何指定在命令行上設置邊界?使用多個空格是一種可視化幫助,但是當您的shell解析命令執行時,多個空格不會有幫助。所以你的Python應用程序只會收到:-a 1 -b 2 -c 3 -a 4 -c 6 -b 8 -a 10'。你現在如何定義集合?這是一個有效的假設,每個集合的元素都是排序的,所以你會知道你已經達到了另一個集合,因爲你之前有_c_,現在你已經達到了_a_? – farzad 2014-10-09 03:44:43

+0

空間只是爲了清楚地展示可能的互動。我同意沒有一個好的方法可以在沒有必要的論據的情況下將它們分解成集合,謝謝你指出這一點,我應該提到-a是一個必需的參數,這讓我們可以確定集合的邊界。我想簡單地爲每個參數使用list並將它們作爲元組壓縮,但是當缺少一些可選參數時,這將不正確。 – user3043805 2014-10-09 03:57:38

回答

2

使論點重複的方法是使用 '追加' 動作類型:

import argparse 
parser = argparse.ArgumentParser() 
parser.add_argument('-a', action='append') 
parser.add_argument('-b', action='append') 
parser.add_argument('-c', action='append') 
argv = '-a 1 -b 2 -c 3 -a 4 -c 6 -a 7 -b 8 -a 10' 
args = parser.parse_args(argv.split()) 
print args 

生產:

Namespace(a=['1', '4', '7', '10'], b=['2', '8'], c=['3', '6']) 

不幸的是它確實失去了一些信息。沒有辦法將'4'與'6'關聯起來而不是'8'。如果是

Namespace(a=1, b=2, c=3) 
Namespace(a=4, c=6) 
Namespace(a=7, b=8) 
Namespace(a=10) 

[{'a': 1, 'c': 3, 'b': 2}, 
{'a': 4, 'c': 6}, 
{'a': 7, 'b': 8}, 
{'a': 10}] 

我不知道: -

如果使用「」分隔的參數塊,那麼這個反覆解析器可以做的工作:

parser = argparse.ArgumentParser() 
# SUPPRESS keeps the default None out of the namespace 
parser.add_argument('-a', type=int, default=argparse.SUPPRESS, required=True) 
parser.add_argument('-b', type=int, default=argparse.SUPPRESS) 
parser.add_argument('-c', type=int, default=argparse.SUPPRESS) 
argv = '-a 1 -b 2 -c 3 -- -a 4 -c 6 -- -a 7 -b 8 -- -a 10' 

arglist = [] 
rest = argv.split() 
while rest: 
    args,rest = parser.parse_known_args(rest) 
    rest = rest[1:] # remove the 1st '--' 
    print args 
    arglist.append(vars(args)) 
print arglist 

生產足夠強大。我需要-a,所以從其中一個組中忽略它會引發錯誤。


或調整法扎德的迭代器:

def by_sets(iterator, start): 
    set = [] 
    for val in iterator: 
     if set and val == start: 
      yield set 
      set = [val] 
     else: 
      set.append(val) 
    yield set 

argv = '-a 1 -b 2 -c 3 -a 4 -c 6 -a 7 -b 8 -a 10' 
# print list(by_sets(argv.split(), '-a')) 
# [['-a', '1', '-b', '2', '-c', '3'], ['-a', '4', '-c', '6'],... ['-a', '10']] 

arglist = [] 
for aset in by_sets(argv.split(), '-a'): 
    arglist.append(vars(parser.parse_args(aset))) 
print arglist 

生產:

[{'a': 1, 'c': 3, 'b': 2}, {'a': 4, 'c': 6}, {'a': 7, 'b': 8}, {'a': 10}] 

循環也可以寫成理解:

[vars(parser.parse_args(aset)) for aset in by_sets(argv.split(), '-a')] 
+0

非常感謝,接受hpaulj的解決方案,因爲這個問題是具體的。,儘管farzad提供了有用的評論和代碼。謝謝你們倆 – user3043805 2014-10-09 21:09:00

1

我們可以遍歷命令行參數,並通過一個將它們添加一個設定的,如果我們達到「-a」這會被解析爲字典列表這標誌着另一組的開始,我們將創建一個新組。雖然此代碼示例不檢查無效的用戶輸入。

import sys 

def get_pairs(iterator, start): 
    sets = [] 
    for val in iterator: 
     if val == start: 
      sets.append({}) 
     sets[-1][val] = next(iterator) 
    return sets 

print get_pairs(iter(sys.argv[1:]), '-a')