2015-05-13 45 views
5

這裏是我想要做的: 一個看起來像git命令行爲的命令。無論您是輸入git commit還是git checkout,都無法獲得相同的選項。 但在我的情況,我想提供基於一個參數值(文件名)這樣的不同的參數:Python argparse,基於父參數值提供不同的參數

>cmd file.a -h 
usage: cmd filename [-opt1] [-opt2] 
positional arguments: 
filename   file to process 
optional arguments: 
-opt1   do something on files of type 'a' 
-opt2   do something else on files of type 'a' 

>cmd file.b -h 
usage: cmd filename [-opt3] [-opt4] 
positional arguments: 
filename   file to process 
optional arguments: 
-opt3   do something on files of type 'b' 
-opt4   do something else on files of type 'b' 

是否有可能做這種使用Python和argparse的事情嗎?
我試過到目前爲止是:

parser = argparse.Argument_parser(prog='cmd') 
subparsers = parser.add_subparsers() 

parser.add_argument('filename', 
        help="file or sequence to process") 

args = parser.parse_args(args=argv[1:]) 

sub_parser = subparsers.add_parser(args.filename, help="job type") 
base, ext = os.path.splitext(args.filename) 
if ext == 'a': 
    sub_parser.add_argument("-opt1", action='store_true') 
    sub_parser.add_argument("-opt2", action='store_true') 
elif ext == 'b': 
    sub_parser.add_argument("-opt3", action='store_true') 
    sub_parser.add_argument("-opt4", action='store_true') 

args = parser.parse_args(args=argv[1:]) 

我不知道我是否應該使用subparsers或兒童解析器或羣體,我有點失去了通過argparse

+0

根據您想要看到的行爲,聽起來好像是一個子分析器是您想要去的方式。 –

回答

14
提供的所有可能性

當您看一看parse_args() implementation時,您會注意到它會一次解析所有參數(它不會使用yield來持續生成狀態),因此您必須先準備好結構,而不要在解析半數參數之後做好準備。

Taking from official example in the docs你應該開始解析這樣的前添加子分析器(S):

import argparse 

parser = argparse.ArgumentParser(prog='PROG') 
subparsers = parser.add_subparsers(help='sub-command help') 

# create the parser for the "a" command 
parser_a = subparsers.add_parser('a', help='a help') 
parser_a.add_argument("--opt1", action='store_true') 
parser_a.add_argument("--opt2", action='store_true') 

# create the parser for the "b" command 
parser_b = subparsers.add_parser('b', help='b help') 
parser_b.add_argument("--opt3", action='store_true') 
parser_b.add_argument("--opt4", action='store_true') 

# parse some argument lists 
print(parser.parse_args()) 

和輸出(命令行),幫助是很好的印刷:

D:\tmp>s.py -h 
usage: PROG [-h] {a,b} ... 

positional arguments: 
    {a,b}  sub-command help 
    a   a help 
    b   b help 

optional arguments: 
    -h, --help show this help message and exit 

A自變量解析

D:\tmp>s.py a --opt1 
Namespace(opt1=True, opt2=False) 

參數與ARGS解析

D:\tmp>s.py b 
Namespace(opt3=False, opt4=False) 

另外:

D:\tmp>s.py b --opt2 
usage: PROG [-h] {a,b} ... 
PROG: error: unrecognized arguments: --opt2 

D:\tmp>s.py b --opt3 
Namespace(opt3=True, opt4=False) 

導致錯誤運行參數


此外,如果你需要identify which subparser使用您可以添加到dest=name電話parser.add_subparsers()我認爲這是不正常強調在文檔):

subparsers = parser.add_subparsers(help='sub-command help', dest='subparser_name') 

有了結果:

D:\tmp>s.py b --opt3 
Namespace(opt3=True, opt4=False, subparser_name='b') 

如果您需要真正動態創建參數(例如負荷昂貴資源的一些參數選項),你可以使用parse_known_args()

Sometimes a script may only parse a few of the command-line arguments, passing the remaining arguments on to another script or program. In these cases, the parse_known_args() method can be useful. It works much like parse_args() except that it does not produce an error when extra arguments are present. Instead, it returns a two item tuple containing the populated namespace and the list of remaining argument strings.

畢竟,parse_args()只檢查後aruments:

def parse_args(self, args=None, namespace=None): 
    args, argv = self.parse_known_args(args, namespace) 
    if argv: 
     msg = _('unrecognized arguments: %s') 
     self.error(msg % ' '.join(argv)) 
    return args 

然後您就可以在argv上重新執行另一個解析器,但我可以想象出幾個可以解決的問題,我不會推薦它,直到真的需要

+0

真棒回答。享受你的新徽章。 –

+0

重新讀一遍。在這裏發現仍然層層的迷人:) –