2016-12-14 48 views
3

我想提出的是支持的格式argparse:扁平化作用的結果=「追加」

./myscript --env ONE=1,TWO=2 --env THREE=3 

這裏的參數列表的腳本是我的嘗試:

import argparse 
parser = argparse.ArgumentParser() 
parser.add_argument(
    '--env', 
    type=lambda s: s.split(','), 
    action='append', 
) 
options = parser.parse_args() 
print options.env 

$ ./myscript --env ONE=1,TWO=2 --env THREE=3 
[['ONE=1', 'TWO=2'], ['THREE=3']] 

當然我可以在後處理解決這個問題:

options.env = [x for y in options.env for x in y] 

,但我不知道是否有某種方式直接從argparse得到扁平名單,讓我不要我必須在我的腦海中保留一份「事後需要平息的事情」的清單,因爲我正在爲該計劃添加新的選項。

如果我使用nargs='*'而不是type=lambda...,則同樣的問題適用。

import argparse 
parser = argparse.ArgumentParser() 
parser.add_argument(
    '--env', 
    nargs='+', 
    action='append', 
) 
options = parser.parse_args() 
print options.env 

$ ./myscript --env ONE=1 TWO=2 --env THREE=3 
[['ONE=1', 'TWO=2'], ['THREE=3']] 
+0

在這裏找到了一些解決方法:http://stackoverflow.com/questions/19228516/python-argparse-with-nargs-behaviour-incorrect但我沒有實際使用在生產代碼。 – Quuxplusone

+0

在生產代碼中使用解決方法的標準是什麼? – hpaulj

回答

3

不幸的是,默認情況下沒有在ArgumentParser提供的extend行動。但它不是太難註冊一個:

import argparse 

class ExtendAction(argparse.Action): 

    def __call__(self, parser, namespace, values, option_string=None): 
     items = getattr(namespace, self.dest) or [] 
     items.extend(values) 
     setattr(namespace, self.dest, items) 


parser = argparse.ArgumentParser() 
parser.register('action', 'extend', ExtendAction) 
parser.add_argument('--env', nargs='+', action='extend') 

args = parser.parse_args() 
print(args) 

演示:

$ python /tmp/args.py --env one two --env three 
Namespace(env=['one', 'two', 'three']) 

lambda你在你的例子是有點的type kwarg的預期使用情況之外。所以,我會建議在空白處分割,因爲正確處理,實際上在數據中的情況會很痛苦。如果拆分的空間,你免費得到這個功能:

$ python /tmp/args.py --env one "hello world" two --env three 
Namespace(env=['one', 'hello world', 'two', 'three']) 
1

extend動作類已要求(http://bugs.python.org/issue23378),但因爲它很容易將永遠被添加自己的,我不認爲該功能添加。

一個常見的Python成語壓扁列表使用chain

In [36]: p=[['x'], ['y']] 
In [37]: from itertools import chain 
In [38]: chain(*p) 
Out[38]: <itertools.chain at 0xb17afb2c> 
In [39]: list(chain(*p)) 
Out[39]: ['x', 'y'] 

你的列表中理解是等價的:

In [40]: [x for y in p for x in y] 
Out[40]: ['x', 'y'] 

http://bugs.python.org/issue16399#msg277919我建議另一種可能 - 爲append定製default值論據。

class MyList(list): 
    def append(self,arg): 
     if isinstance(arg,list): 
      self.extend(arg) 
     else: 
      super(MyList, self).append(arg) 

parser = argparse.ArgumentParser() 
a = parser.add_argument('-f', action='append', nargs='*',default=MyList([])) 
args = parser.parse_args('-f 1 2 3 -f 4 5'.split()) 

產生

Namespace(f=['1', '2', '3', '4', '5']) 

你將不得不使用自己的判斷什麼是產品代碼適當。