【问题标题】:argparse optional parameter within positional位置中的 argparse 可选参数
【发布时间】:2014-12-29 03:57:42
【问题描述】:

使用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)

【问题讨论】:

  • 14191 中有一个解决方法的版本,您可以下载并添加到您的代码中 - 无需修改您的 argparse。如果您需要定义更多positionals,您可能需要它。

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


【解决方案1】:

您可以使用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)

【讨论】:

    【解决方案2】:

    你想要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)
    

    不需要迭代,因为optionals 是第一次处理。 unknown 中剩下的就是files

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

    【讨论】:

      猜你喜欢
      • 2011-05-27
      • 2023-04-02
      • 2019-04-13
      • 2018-02-20
      • 1970-01-01
      • 1970-01-01
      • 2015-06-16
      相关资源
      最近更新 更多