位置内的argparse可选参数

时间:2014-11-02 10:18:29

标签: python python-3.x command-line-arguments argparse

使用argparse我希望能够将可选参数与多个位置参数混合,例如svn允许:

svn ls first/path -r 1000 second/path

目前,Python尚未正式支持(c.f。http://bugs.python.org/issue14191)。我写了这个解决方法,我现在想知道,如果a)有更好/更容易/更优雅的方式来做到这一点,并且b)如果有人可以在代码中看到可能在某些情况下破坏它的东西:

#!/usr/bin/env python3                                                          

import argparse as ap                                                           

p = ap.ArgumentParser()                                                         
p.add_argument('-v', action='store_true')                                       
p.add_argument('-l', action='store_true')                                       
p.add_argument('files', nargs='*', action='append')                             
p.add_argument('remainder', nargs=ap.REMAINDER, help=ap.SUPPRESS)                  

args = p.parse_args()                                                              
while args.remainder != []:                                                        
    args = p.parse_args(args.remainder, args)                                      

print(args)  

用法示例:

./test.py a b -v c d 

输出:

Namespace(files=[['a', 'b'], ['c', 'd']], l=False, remainder=[], v=True)

2 个答案:

答案 0 :(得分:2)

您可以使用parse_known_args代替remainder

import argparse as ap                                                           

p = ap.ArgumentParser()                                                         
p.add_argument('-v', action='store_true')                                       
p.add_argument('-l', action='store_true')                                       
p.add_argument('files', nargs='*', action='append')                             

args, unknown = p.parse_known_args()
while unknown:
    args, unknown = p.parse_known_args(unknown, args) 

print(args)

产量

Namespace(files=[['a', 'b'], ['c', 'd']], l=False, v=True)

答案 1 :(得分:0)

您想要files=[['a', 'b'], ['c', 'd']]还是files=['a', 'b', 'c', 'd']?换句话说应该

./test.py a b -v c d 
./test.py a b -v c -l d 
./test.py -l a b -v c d 

提供不同的files列表清单。

具有append位置的

*通常没有意义,因为您无法重复位置参数。但是使用这个递归应用程序,它确实有效。但如果子列表很重要,为什么不使用多个位置参数。

另一方面,要获得“文件”的平面列表,您可以做几件事:

您可以在解析后展平列表(例如args.files=list(itertools.chain(*args.files))

您可以使用p.add_argument('files', nargs='?', action='append')。这会迭代每个file字符串。

./test.py a b -l c d -v e f
Namespace(files=['a', 'b', 'c', 'd', 'e', 'f'], l=True, remainder=[], v=True)

您可以通过从初始解析中删除位置来复制http://bugs.python.org/issue14191补丁。在这种情况下,extras可以简单地插入args

这样做的一个缺点是usagehelp对位置一无所知,需要自定义usage和/或description参数。

usage = usage: %(prog)s [-h] [-v] [-l] [files [files ...]]
description = 'files: may be given in any order'
p = ap.ArgumentParser(usage=usage, description=description)                            
p.add_argument('-v', action='store_true')                                       
p.add_argument('-l', action='store_true')                                       
args, extras = p.parse_known_args() 
args.files = extras

unutbu的答案不保留分组。他们第一次失败了:

命名空间(files = [['a','b'],['c','d','e','f']],l = True,v = True)

可以改为提供一个单一的列表:

p = ap.ArgumentParser()
p.add_argument('-v', action='store_true')
p.add_argument('-l', action='store_true')
p.add_argument('files', nargs='*')

args, unknown = p.parse_known_args()
args.files.extend(unknown)

不需要迭代,因为第一次处理optionalsunknown中剩下的所有内容都是files

总之 - 为了保留分组,您的解决方案似乎是最好的。