2013-01-18 17 views
5

使用argparse(或其他?)我希望每個位置參數都有一個帶有默認值的可選參數。每個位置參數的可選參數

的參數會像這樣:

script.py arg1 arg2 -o 1 arg3 -o 2 arg4 arg5 

,我希望它來解析到的東西可用,像的位置參數列表和可選參數與填充默認列表這一點。例如如果可選默認在上面的例子中是0:

positional = [arg1, arg2, arg3, arg4, arg5] 
optional = [0, 1, 2, 0, 0] 
換句話說

parser.add_argument('-o', action='append')是不是我想要的,因爲我失去了位置參數,每一個可選的參數相關聯。

+0

你知道有多少位置參數嗎? – mgilson

+0

不,我想循環參數,不管有多少。 – bkanuka

回答

3

這裏有一個簡單的黑客,我放在一起,可能是一個合理的地方開始:

import argparse 

class PositionalAction(argparse.Action): 
    def __call__(self,parser,namespace,values,option_string=None): 
     lst = getattr(namespace,self.dest) 
     lst.append(values) 
     parser.last_positional_values = lst 
     all_positional = getattr(namespace,'all_positional',[]) 
     all_positional.append(lst) 
     namespace.all_positional = all_positional 

class AssociateAction(argparse.Action): 
    def __call__(self,parser,namespace,values,option_string=None): 
     try: 
      parser.last_positional_values.append(values) 
     except AttributeError: 
      pass 

parser = argparse.ArgumentParser() 
parser.add_argument('-o',action=AssociateAction,dest=argparse.SUPPRESS) 
junk,unknown = parser.parse_known_args() 

for i,_ in enumerate(unknown): 
    parser.add_argument('arg%d'%i,action=PositionalAction,default=[]) 

print parser.parse_args() 

這裏,它是在行動:

temp $ python test1.py foo -o 1 bar -o 2 baz qux -o 4 
Namespace(all_positional=[['foo', '1'], ['bar', '2'], ['baz'], ['qux', '4']], arg0=['foo', '1'], arg1=['bar', '2'], arg2=['baz'], arg3=['qux', '4']) 

這個問題有一些挑戰。首先,你想接受任意數量的位置參數 - argparse不喜歡那樣。 argparse想知道前面會發生什麼。解決方案是構建一個解析器並解析命令行,但要告訴argparse僅解析已知參數(在這種情況下,無位置-o參數都是靜默解析,但「位置」參數未解析。) 。 parse_known_args非常適合此操作,因爲它返回形式爲(namespace_of_parsed_stuff, uknown_args)的元組。所以現在我們知道未知的參數 - 我們只需要爲解析器添加一個位置參數,以使parse_args高興。

現在,實際執行的自定義操作是什麼?當找到位置參數時(第二遍),我們得到默認值(這是一個列表)並將該值添加到該列表中(以下我將稱之爲「值」列表)。然後,我們修改解析器並參考「值」列表。我們還從命名空間中獲得「all_positional」列表。如果它沒有這個屬性,我們只是得到一個空的列表。我們將「value」列表添加到「all_positional」列表中並放回到名稱空間中。

現在,當我們點擊一​​個-o標誌時,我們看解析器來獲取「值」列表,並且將附加值添加到該列表中。我們可以在不觸及解析器的情況下做同樣的事情......(我們可以看看namespace.all_positional[-1] - 與parser.last_positional_values的列表相同)。

+0

你製作的這個魔法似乎是按照我想要的(或者足夠接近)來做,但是我需要一段時間才能完全理解你所做的。無論如何,謝謝! – bkanuka

+0

我會添加一些關於發生了什麼的評論,希望能夠幫助它更容易理解。 – mgilson

+0

別擔心,誤解當然更多的是因爲缺乏專業知識而不是缺乏明確性。 – bkanuka

-1

使用optparse,它的強大,如果稍微有點複雜:

op = optparse.OptionParser(usage=usage) 

op.add_option('-c','--cmd',dest='cmd',help="""Command to run. Mutually exclusive with -s. You can use string ${ADDR} to have it replaced with specified host address in the command. """) 

op.add_option('-s','--script',dest='script',help="""Script file to run remotely. Mutually exclusive with -c. A script can have its own arguments; specify the whole command in doublequotes, like "script -arg arg".""") 

op.add_option('-l','--replicate-owner',dest='replicateowner',action="store_true",help="""Replicate (symbolic) owner and (symbolic) group of the file on the remote host, if possible. If remote account with username the same as local account does not exist on remote host, this will silently fail.""") 

# parse cmdline options 
(opts, args) = op.parse_args() 

OPTS讓你命名ARGS和args讓你的位置ARGS。

您可以使用位置參數來取值或設置true或false以及更多的IIRC。

+2

這不回答具體問題。一般來說,海報似乎意識到如何使用{opt,arg}解析。 – chepner

0

如何簡單地通過sys.argv自己。您似乎不需要argparse提供的額外功能。例如:

argv='script.py arg1 arg2 -o 1 arg3 -o 2 arg4 arg5'.split() 
pos=[] 
opt=[] 
i=1 
while i<len(argv): 
    a=argv[i] 
    if a[:2]!='-o': 
     pos.append(a) 
     opt.append(0) 
    else: 
     i += 1 
     opt[-1]=argv[i] 
    i += 1