协慌网

登录 贡献 社区

用 argparse 解析布尔值

我想使用 argparse 解析布尔命令行参数,写为 “--foo True” 或 “--foo False”。例如:

my_program --my_boolean_flag False

但是,以下测试代码不能满足我的要求:

import argparse
parser = argparse.ArgumentParser(description="My parser")
parser.add_argument("--my_bool", type=bool)
cmd_line = ["--my_bool", "False"]
parsed_args = parser.parse(cmd_line)

可悲的是, parsed_args.my_bool计算结果为True 。即使当我将cmd_line更改为["--my_bool", ""] ,也是如此,这很令人惊讶,因为bool("")评估为False

如何获取 argparse 来解析"False""F"及其小写变体为False

答案

我认为更规范的方法是通过:

command --feature

command --no-feature

argparse很好地支持此版本:

parser.add_argument('--feature', dest='feature', action='store_true')
parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)

当然,如果您真的想要--arg <True|False>版本,则可以将ast.literal_eval传递为 “类型”,或者传递用户定义的函数...

def t_or_f(arg):
    ua = str(arg).upper()
    if 'TRUE'.startswith(ua):
       return True
    elif 'FALSE'.startswith(ua):
       return False
    else:
       pass  #error condition maybe?

另一个解决方案使用先前的建议,但带有argparse的 “正确” 解析错误:

def str2bool(v):
    if isinstance(v, bool):
       return v
    if v.lower() in ('yes', 'true', 't', 'y', '1'):
        return True
    elif v.lower() in ('no', 'false', 'f', 'n', '0'):
        return False
    else:
        raise argparse.ArgumentTypeError('Boolean value expected.')

这对于使用默认值进行切换非常有用。例如

parser.add_argument("--nice", type=str2bool, nargs='?',
                        const=True, default=False,
                        help="Activate nice mode.")

允许我使用:

script --nice
script --nice <bool>

并仍使用默认值(特定于用户设置)。这种方法的一个(间接相关的)缺点是 “水罐” 可能会引起位置争执 - 请参阅此相关问题此 argparse 错误报告

如果要同时允许--feature--no-feature (最后一个获胜)

这使用户可以使用--feature来创建 shell 别名,并使用--no-feature覆盖它。

Python 3.9 及更高版本

parser.add_argument('--feature', default=True, action=argparse.BooleanOptionalAction)

Python 3.8 及以下

我建议 mgilson 的答案:

parser.add_argument('--feature', dest='feature', action='store_true')
parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)

如果您不想同时允许--feature--no-feature

您可以使用互斥组:

feature_parser = parser.add_mutually_exclusive_group(required=False)
feature_parser.add_argument('--feature', dest='feature', action='store_true')
feature_parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)

如果要设置许多帮助器,则可以使用此帮助器:

def add_bool_arg(parser, name, default=False):
    group = parser.add_mutually_exclusive_group(required=False)
    group.add_argument('--' + name, dest=name, action='store_true')
    group.add_argument('--no-' + name, dest=name, action='store_false')
    parser.set_defaults(**{name:default})

add_bool_arg(parser, 'useful-feature')
add_bool_arg(parser, 'even-more-useful-feature')