使用argparse和多个-v选项的详细级别

Cha*_*net 34 python argparse

我希望能够通过向命令行添加更多-v选项来指定不同的详细级别.例如:

$ myprogram.py    
$ myprogram.py -v
$ myprogram.py -vv
$ myprogram.py -v -v -v
Run Code Online (Sandbox Code Playgroud)

会导致verbose = 0,verbose = 1,verbose = 2,verbose = 3.如何使用argparse实现这一目标?

可选地,它也可以很好地指定它

$ myprogram -v 2
Run Code Online (Sandbox Code Playgroud)

Ben*_*Ben 102

我完全有这个愿望,并且几个月前实现了一个自定义操作来实现它,我厌倦了复制到我一直在写的脚本.但我刚刚发现argparse确实支持action='count',就像optparse那样,尽管这似乎在标准库docs online中完全没有记录(这个bug报告指出缺席;一个补丁已经发布和审查,所以可能有一天它会出现.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', action='count', default=0)

for c in ['', '-v', '-v -v', '-vv', '-vv -v', '-v -v --verbose -vvvv']:
    print parser.parse_args(c.split())
Run Code Online (Sandbox Code Playgroud)

输出:

Namespace(verbose=0)
Namespace(verbose=1)
Namespace(verbose=2)
Namespace(verbose=2)
Namespace(verbose=3)
Namespace(verbose=7)
Run Code Online (Sandbox Code Playgroud)

唯一非常小的问题是你必须明确设置,default=0如果你不想让任何-v参数给你一个详细级别为0而不是None.

  • 这不允许`myprogram -v 2`语法.与此同时,'action ='count'`出现在文档中. (4认同)
  • 这似乎是对OP问题的最佳和最简单的答案。 (4认同)

unu*_*tbu 20

您可以使用nargs='?'(在-v标志后接受0或1个参数)和自定义操作(处理0或1参数):

import sys
import argparse

class VAction(argparse.Action):
    def __init__(self, option_strings, dest, nargs=None, const=None, 
                 default=None, type=None, choices=None, required=False, 
                 help=None, metavar=None):
        super(VAction, self).__init__(option_strings, dest, nargs, const, 
                                      default, type, choices, required, 
                                      help, metavar)
        self.values = 0
    def __call__(self, parser, args, values, option_string=None):
        # print('values: {v!r}'.format(v=values))
        if values is None:
            self.values += 1
        else:
            try:
                self.values = int(values)
            except ValueError:
                self.values = values.count('v')+1
        setattr(args, self.dest, self.values)

# test from the command line
parser = argparse.ArgumentParser()
parser.add_argument('-v', nargs='?', action=VAction, dest='verbose')
args = parser.parse_args()
print('{} --> {}'.format(sys.argv[1:], args))

print('-'*80)

for test in ['-v', '-v -v', '-v -v -v', '-vv', '-vvv', '-v 2']:
    parser = argparse.ArgumentParser()
    parser.add_argument('-v', nargs='?', action=VAction, dest='verbose')
    args=parser.parse_args([test])
    print('{:10} --> {}'.format(test, args))
Run Code Online (Sandbox Code Playgroud)

运行script.py -v -v在命令行收率

['-v', '-v'] --> Namespace(verbose=2)
--------------------------------------------------------------------------------
-v         --> Namespace(verbose=1)
-v -v      --> Namespace(verbose=2)
-v -v -v   --> Namespace(verbose=3)
-vv        --> Namespace(verbose=2)
-vvv       --> Namespace(verbose=3)
-v 2       --> Namespace(verbose=2)
Run Code Online (Sandbox Code Playgroud)

取消注释print语句以更好地了解VAction正在执行的操作.

  • 不再需要自定义操作.看**本**的答案. (2认同)

FMc*_*FMc 12

您可以处理问题的第一部分append_const.否则,你可能会被写一个自定义动作,正如unutbu的精细回答中所建议的那样.

import argparse

ap = argparse.ArgumentParser()
ap.add_argument('-v', action = 'append_const', const = 1)

for c in ['', '-v', '-v -v', '-vv', '-vv -v']:
    opt = ap.parse_args(c.split())
    opt.v = 0 if opt.v is None else sum(opt.v)
    print opt
Run Code Online (Sandbox Code Playgroud)

输出:

Namespace(v=0)
Namespace(v=1)
Namespace(v=2)
Namespace(v=2)
Namespace(v=3)
Run Code Online (Sandbox Code Playgroud)

  • 使用`append_const`还可以添加`-q`参数.使用`dest ='v',const = -1`,它将撤消任何`-v`.我用`default = [2]`使用它,所以我可以将结果映射到记录模块级别,从WARN开始,让你-q/v上下缩放. (3认同)
  • 我喜欢这个解决方案;我认为使用 `append_const` 提供的代码简单性值得放弃 `-v 2`。 (2认同)

Eri*_*itt 7

这是我对此的看法,它不使用任何新类,适用于 Python 2 和 3,并支持使用“-v”/“--verbose”和“-q”/“--quiet”从默认值进行相对调整,但它支持使用数字,例如“-v 2”:

#!/usr/bin/env python
import argparse
import logging
import sys

LOG_LEVELS = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
DEFAULT_LOG_LEVEL = "INFO"


def main(argv):
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--verbose", "-v",
        dest="log_level",
        action="append_const",
        const=-1,
    )
    parser.add_argument(
        "--quiet", "-q",
        dest="log_level",
        action="append_const",
        const=1,
    )

    args = parser.parse_args(argv[1:])
    log_level = LOG_LEVELS.index(DEFAULT_LOG_LEVEL)

    # For each "-q" and "-v" flag, adjust the logging verbosity accordingly
    # making sure to clamp off the value from 0 to 4, inclusive of both
    for adjustment in args.log_level or ():
        log_level = min(len(LOG_LEVELS) - 1, max(log_level + adjustment, 0))

    log_level_name = LOG_LEVELS[log_level]
    print(log_level_name)
    logging.getLogger().setLevel(log_level_name)


if __name__ == "__main__":
    main(sys.argv)
Run Code Online (Sandbox Code Playgroud)

例子:

$ python2 verbosity.py -vvv
DEBUG
$ python3 verbosity.py -vvv -q
INFO
$ python2 verbosity.py -qqq -vvv -q
WARNING
$ python2 verbosity.py -qqq
CRITICAL
Run Code Online (Sandbox Code Playgroud)