我想使用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解析“假”,“F”,和他们的小写变体为假?


当前回答

使用前面建议的另一个解决方案,但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>

并且仍然使用默认值(特定于用户设置)。这种方法的一个(间接相关的)缺点是'nargs'可能会捕获一个位置参数——请参阅这个相关问题和这个argparse错误报告。

其他回答

您可以创建一个BoolAction,然后使用它

class BoolAction(Action):
    def __init__(
            self,
            option_strings,
            dest,
            nargs=None,
            default: bool = False,
            **kwargs,
    ):
        if nargs is not None:
            raise ValueError('nargs not allowed')
        super().__init__(option_strings, dest, default=default, **kwargs)

    def __call__(self, parser, namespace, values, option_string=None):
        input_value = values.lower()
        b = input_value in ['true', 'yes', '1']
        if not b and input_value not in ['false', 'no', '0']:
            raise ValueError('Invalid boolean value "%s".)
        setattr(namespace, self.dest, b)

然后在parser.add_argument()中设置action=BoolAction

我认为更规范的做法是:

command --feature

and

command --no-feature

Argparse很好地支持这个版本:

Python 3.9 +:

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

Python < 3.9:

parser.add_argument('--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>

并且仍然使用默认值(特定于用户设置)。这种方法的一个(间接相关的)缺点是'nargs'可能会捕获一个位置参数——请参阅这个相关问题和这个argparse错误报告。

这其实已经过时了。对于Python 3.7+, Argparse现在支持布尔参数(search BooleanOptionalAction)。

实现如下所示:

import argparse

ap = argparse.ArgumentParser()

# List of args
ap.add_argument('--foo', default=True, type=bool, help='Some helpful text that is not bar. Default = True')

# Importable object
args = ap.parse_args()

还有一件事需要提到:这将阻塞通过argparse.ArgumentTypeError参数的除True和False以外的所有条目。如果您出于任何原因想要尝试更改它,您可以为此创建一个自定义错误类。

简单的。它不灵活,但我更喜欢简单。

  parser.add_argument('--boolean_flag',
                      help='This is a boolean flag.',
                      type=eval, 
                      choices=[True, False], 
                      default='True')

编辑:如果你不相信输入,不要使用eval。