Argparse可选布尔值

2022-05-06 00:00:00 python python-3.x argparse

问题描述

我正在尝试获取以下行为:

  • python test.py⟹存储foo=False
  • python test.py --foo⟹商店foo=True
  • python test.py --foo bool⟹商店foo=bool

当我使用时它起作用

parser.add_argument('--foo', nargs='?', default=False, const=True)

但是,如果我添加type=bool,试图强制强制转换为Boolean,它就会中断。在这种情况下

python test.py --foo False

实际上存储了foo=True。怎么回事??


解决方案

是否确实需要该模式?--foo--foo <value>对于布尔开关而言,不是常用模式。

对于您的问题,请记住命令行值是字符串,type=bool表示您希望应用bool(entered-string-value)。对于--foo False意味着bool("False"),生成True;所有非空字符串都为真!另请参阅Why is argparse not parsing my boolean flag correctly?。

不支持--foo/--foo <string value>,我强烈建议您使用--foo表示True,删除参数值,并添加--no-foo选项以显式设置False

parser.add_argument('--foo', default=False, action='store_true')
parser.add_argument('--no-foo', dest='foo', action='store_false')

dest='foo'开关上的dest='foo'加法可确保它存储的False值(通过store_false)在相同的args.foo属性上结束。

从Python3.9开始,您还可以使用argparse.BooleanOptionalAction操作类:

parser.add_argument("--foo", action=argparse.BooleanOptionalAction)

和它将具有相同的效果,处理--foo--no-foo来设置和清除该标志。

如果您有将foo设置为True的其他配置机制,并且需要使用命令行开关再次覆盖它,则只需要--foo / --no-foo组合。--no-<option>是反转布尔命令行开关的广泛采用的标准。

如果不特别需要--no-foo倒置开关(因为只需省略--foo就意味着‘False’),则只需使用action='store_true'选项即可。这使您的命令行简单明了!

但是,如果您用例或其他约束明确要求您的命令行必须具有某种--foo (true|false|0|1)支持,则添加您自己的转换器:

def str_to_bool(value):
    if isinstance(value, bool):
        return value
    if value.lower() in {'false', 'f', '0', 'no', 'n'}:
        return False
    elif value.lower() in {'true', 't', '1', 'yes', 'y'}:
        return True
    raise ValueError(f'{value} is not a valid boolean value')

parser.add_argument('--foo', type=str_to_bool, nargs='?', const=True, default=False)
  • const值用于省略参数值的nargs='?'参数。在这里,当使用--foo时设置。
  • default=False在根本不使用开关时使用。
  • type=str_to_bool用于处理--foo <value>案例。

演示:

$ cat so52403065.py
from argparse import ArgumentParser

parser = ArgumentParser()

def str_to_bool(value):
    if value.lower() in {'false', 'f', '0', 'no', 'n'}:
        return False
    elif value.lower() in {'true', 't', '1', 'yes', 'y'}:
        return True
    raise ValueError(f'{value} is not a valid boolean value')

parser.add_argument('--foo', type=str_to_bool, nargs='?', const=True, default=False)

print(parser.parse_args())
$ python so52403065.py
Namespace(foo=False)
$ python so52403065.py --foo
Namespace(foo=True)
$ python so52403065.py --foo True
Namespace(foo=True)
$ python so52403065.py --foo no
Namespace(foo=False)
$ python so52403065.py --foo arrbuggrhellno
usage: so52403065.py [-h] [--foo [FOO]]
so52403065.py: error: argument --foo: invalid str_to_bool value: 'arrbuggrhellno'

相关文章