Argparse 可选布尔值

Argparse optional boolean

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

当我使用

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

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

python test.py --foo False

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

对于布尔参数,您应该使用 action='store_true' 参数:

parser.add_argument('--foo', action='store_true')

所以没有--foo选项:

python test.py

将导致 foo 参数的值为 False,并且存在 --foo 选项:

python test.py --foo

将导致 foo 参数的值为 True

确定您需要那个图案吗? --foo--foo <value> 一起用于布尔开关,不是常用的模式。

至于您的问题,请记住命令行值为 字符串 并且 type=bool 表示您希望应用 bool(entered-string-value)。对于 --foo False,这意味着 bool("False"),产生 True;所有非空字符串都是真的!另见

我不支持 --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')

--no-foo 开关上的 dest='foo' 确保它存储的 False 值(通过 store_false)以相同的 args.foo 属性结束.

从 Python 3.9 开始,您还可以使用 argparse.BooleanOptionalAction 操作 class:

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 时,这里设置 foo=True
  • 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'