Python 具有argparse和多个-v选项的详细级别
我希望能够通过向命令行添加更多的-v选项来指定不同的详细级别。例如:Python 具有argparse和多个-v选项的详细级别,python,argparse,Python,Argparse,我希望能够通过向命令行添加更多的-v选项来指定不同的详细级别。例如: $ myprogram.py $ myprogram.py -v $ myprogram.py -vv $ myprogram.py -v -v -v 将分别导致verbose=0、verbose=1、verbose=2和verbose=3。如何使用argparse实现这一点 或者,也可以像这样指定它 $ myprogram -v 2 argparse支持append操作,该操作允许您指定多个参数。选中,搜索“ap
$ myprogram.py
$ myprogram.py -v
$ myprogram.py -vv
$ myprogram.py -v -v -v
将分别导致verbose=0、verbose=1、verbose=2和verbose=3。如何使用argparse实现这一点
或者,也可以像这样指定它
$ myprogram -v 2
argparse
支持append
操作,该操作允许您指定多个参数。选中,搜索“append
”您可以使用nargs=”?“
(在-v
标志后接受0或1个参数)和自定义操作(处理0或1个参数):
从命令行运行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)
取消对print语句的注释,以便更好地查看
VAction
正在执行的操作。您可以使用append\u const
处理问题的第一部分。否则,您可能会陷入编写自定义操作的困境,正如罚款中所建议的那样
输出:
Namespace(v=0)
Namespace(v=1)
Namespace(v=2)
Namespace(v=2)
Namespace(v=3)
Namespace(verbose=0)
Namespace(verbose=1)
Namespace(verbose=2)
Namespace(verbose=2)
Namespace(verbose=3)
Namespace(verbose=7)
您第一次提出的方法很可能会混淆。不同详细程度的不同选项名称,或者一个详细程度标志(可选后跟详细程度的数字指示器)不太可能混淆用户,并允许更灵活地分配详细程度。argparse支持: 输出:
Namespace(v=0)
Namespace(v=1)
Namespace(v=2)
Namespace(v=2)
Namespace(v=3)
Namespace(verbose=0)
Namespace(verbose=1)
Namespace(verbose=2)
Namespace(verbose=2)
Namespace(verbose=3)
Namespace(verbose=7)
唯一一个非常小的麻烦是,如果不希望任何
-v
参数为您提供详细级别为0的详细级别,而不是None
扩展unutbu的答案,则必须显式设置default=0
,下面是一个自定义操作,包括处理--quiet/-q组合。这是在Python3中测试的。在Python>=2.7中使用它应该没什么大不了的
class ActionVerbose(argparse.Action):
def __call__(self, parser, args, values, option_string=None):
#print(parser, args, values, option_string)
# Obtain previously set value in case this option call is incr/decr only
if args.verbose == None:
base = 0
else:
base = args.verbose
# One incr/decr is determined in name of option in use (--quiet/-q/-v/--verbose)
option_string = option_string.lstrip('-')
if option_string[0] == 'q':
incr = -1
elif option_string[0] == 'v':
incr = 1
else:
raise argparse.ArgumentError(self,
'Option string for verbosity must start with v(erbose) or q(uiet)')
# Determine if option only or values provided
if values==None:
values = base + incr
else:
# Values might be an absolute integer verbosity level or more 'q'/'v' combinations
try:
values = int(values)
except ValueError:
values = values.lower()
if not re.match('^[vq]+$', values):
raise argparse.ArgumentError(self,
"Option string for -v/-q must contain only further 'v'/'q' letters")
values = base + incr + values.count('v') - values.count('q')
setattr(args, self.dest, values)
@classmethod
def add_to_parser(cls,
parser, dest='verbose', default=0,
help_detail='(0:errors, 1:info, 2:debug)'):
parser.add_argument('--verbose', nargs='?', action=ActionVerbose, dest=dest, metavar='level',
default=default,
help='Increase or set level of verbosity {}'.format(help_detail))
parser.add_argument('-v', nargs='?', action=ActionVerbose, dest=dest, metavar='level',
help='Increase or set level of verbosity')
parser.add_argument('--quiet', nargs='?', action=ActionVerbose, dest=dest, metavar='level',
help='Decrease or set level of verbosity')
parser.add_argument('-q', nargs='?', action=ActionVerbose, dest=dest, metavar='level',
help='Decrease or set level of verbosity')
有一个方便的类方法可用于为--verbose
,-v
,-q
,--quiet
设置所有四个选项处理程序。像这样使用它:
parser = argparse.ArgumentParser()
ActionVerbose.add_to_parser(parser, default=defaults['verbose'])
# add more arguments here with: parser.add_argument(...)
args = parser.parse_args()
使用具有这些参数的脚本时,可以执行以下操作:
./script -vvvvvv -v 4 -v 0 -v -vvv --verbose --quiet 2 -v qqvvqvv
使用此命令行args.verbose
将是4
- 任何带有给定数字的
都是该给定数字(=详细程度)的绝对-v/-q/-verbose/-quiet
参数集
- 任何不带数字的
都是该级别的增量-v/--verbose
- 任何没有数字的
都是该级别的减量-q/--quiet
- 任何
之后都可能立即出现更多-v/-q
字母,产生的级别是v/q
旧级别+sum(count('v'))-sum(count('q'))
- 总体默认值为0
--quiet
将级别重置为0,甚至是-1。为此,请从-q
和-quiet
的add_参数中删除nargs
,如果选项字符串[0]='q',则也可以将硬编码设置为value=0
如果使用错误,正确的解析器错误会很好地打印出来:
./script -vvvvvv -v 4 -v 0 -v -vvv --verbose --quiet 2 -v qqvvqvav
usage: script [-h] [--verbose [level]]
[-v [level]] [--quiet [level]] [-q [level]]
script: error: argument -v: Option string for -v/-q must contain only further 'v'/'q' letters
下面是我对此的看法,它不使用任何新类,在Python 2和3中都可以使用,并且支持使用“-v”/--verbose”和“-q”/--quiet对默认值进行相对调整,但它不支持使用数字,例如“-v2”:
例如:
$ python2 verbosity.py -vvv
DEBUG
$ python3 verbosity.py -vvv -q
INFO
$ python2 verbosity.py -qqq -vvv -q
WARNING
$ python2 verbosity.py -qqq
CRITICAL
我想出了一个替代方案;虽然它并不完全符合OP的要求,但它满足了我的要求,我认为值得分享
使用互斥组计算短选项数或存储长选项的整数值
import argparse
parser = argparse.ArgumentParser()
verbosity_group = parser.add_mutually_exclusive_group()
verbosity_group.add_argument(
'-v',
action='count',
dest='verbosity',
help='Turn on verbose output. Use more to turn up the verbosity level'
)
verbosity_group.add_argument(
'--verbose',
action='store',
type=int,
metavar='N',
dest='verbosity',
help='Set verbosity level to `N`'
)
parser.set_defaults(
verbosity=0
)
parser.parse_args()
如您所见,它允许您“堆叠”单个字符选项,并允许您使用长选项名显式设置值。缺点是不能将long选项用作开关(最后一个示例生成一个异常)。我喜欢这个解决方案;我认为使用append\u const
所提供的代码的简单性值得放弃-v2
。选择我会接受的答案不是一个容易的选择。我喜欢你简单的回答。使用append\u const
还可以添加-q
参数。使用dest='v',const=-1
,它将撤消任何-v
。我将其与default=[2]
一起使用,这样我就可以将结果映射到日志模块级别,从WARN开始,让您在刻度上下移动-q/v。如果您设置allow_abbrev=False
,则-vv
输入不起作用。但是您仍然可以执行-v-v
,这种方法并不少见。例如,SSH使用它,这不允许使用myprogram-v2
语法。同时,action='count'
也出现在文档中。这似乎是对OP问题的最好、最简单的回答。不满足ops的可选要求,但对我来说非常简单和好。谢谢不需要(不再)自定义操作。看看Ben的答案很有教育意义但是。。。未指定时,详细信息为None
(可能需要0
)。当你有其他的选择(不仅仅是一个)并且你想要有自由的参数顺序时,它也不能很好地发挥作用。不幸的是,它甚至不起作用。当您在实际的命令行上多次传递-v
时,您不会得到['-v-v']
,而是得到['-v'、'-v'、'-v']
,因此您的代码给出了verbose=1
@TomaszGandor:感谢您的错误报告。多个<代码> -v>代码> s的问题已经被纠正了。你应该考虑标记为正确答案,因为人们通过谷歌搜索找到这一点,而 -V 2 特性和自定义代码片段对于大多数用户来说都是最重要的。谢谢你的评论,指出了正确的答案。我真的很喜欢这个实现。它非常干净,但也有一些缺陷。您的日志级别与日志库中的日志级别不同,因此仍需要转换它们。
$ python2 verbosity.py -vvv
DEBUG
$ python3 verbosity.py -vvv -q
INFO
$ python2 verbosity.py -qqq -vvv -q
WARNING
$ python2 verbosity.py -qqq
CRITICAL
import argparse
parser = argparse.ArgumentParser()
verbosity_group = parser.add_mutually_exclusive_group()
verbosity_group.add_argument(
'-v',
action='count',
dest='verbosity',
help='Turn on verbose output. Use more to turn up the verbosity level'
)
verbosity_group.add_argument(
'--verbose',
action='store',
type=int,
metavar='N',
dest='verbosity',
help='Set verbosity level to `N`'
)
parser.set_defaults(
verbosity=0
)
parser.parse_args()
parser.parse_args([])
# Namespace(verbosity=0)
parser.parse_args(['-v', '-vv'])
# Namespace(verbosity=3)
parser.parse_args(['--verbose=4'])
# Namespace(verbosity=4)
parser.parse_args(['--verbose'])
# error: argument --verbose: expected one argument