使用 argparse 解析布尔值

2025-01-16 08:38:00
admin
原创
111
摘要:问题描述:我想使用 argparse 来解析写为“--foo True”或“--foo False”的布尔命令行参数。例如:my_program --my_boolean_flag False 但是,以下测试代码并没有实现我想要的效果:import argparse parser = argparse.Arg...

问题描述:

我想使用 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


解决方案 1:

我认为更规范的方法是:

command --feature

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?

解决方案 2:

还有一种解决方案使用了以前的建议,但出现了“正确”的解析错误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 错误报告。

解决方案 3:

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

这允许用户使用 创建 shell 别名--feature,并使用 覆盖它--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')

解决方案 4:

这是另一种没有额外行来设置默认值的变体。布尔值始终被分配,因此可以在逻辑语句中使用它而无需事先检查:

import argparse
parser = argparse.ArgumentParser(description="Parse bool")
parser.add_argument("--do-something", default=False, action="store_true",
                    help="Flag to do something")
args = parser.parse_args()

if args.do_something:
     print("Do something")
else:
     print("Don't do something")

print(f"Check that args.do_something={args.do_something} is always a bool.")

解决方案 5:

一句话:

parser.add_argument('--is_debug', default=False, type=lambda x: (str(x).lower() == 'true'))

解决方案 6:

最简单&最正确的方法是:

from distutils.util import strtobool

parser.add_argument('--feature', dest='feature', 
                    type=lambda x: bool(strtobool(x)))

请注意,True 值为 y、yes、t、true、on 和 1;false 值为 n、no、f、false、off 和 0。如果 val 为其他值,则会引发 ValueError。

解决方案 7:

似乎对type=bool和 的type='bool'含义有些困惑。其中一个(或两个)应该表示“运行函数 ” bool(),还是“返回布尔值”?就目前而言,它type='bool'没有任何意义。 add_argument给出'bool' is not callable错误,就像您使用type='foobar'、 或一样type='int'

argparse确实有注册表允许您定义这样的关键字。它主要用于action,例如“action='store_true'”。您可以使用以下命令查看已注册的关键字:

parser._registries

显示一本字典

{'action': {None: argparse._StoreAction,
  'append': argparse._AppendAction,
  'append_const': argparse._AppendConstAction,
...
 'type': {None: <function argparse.identity>}}

定义了很多动作,但只有一种类型,即默认类型argparse.identity

此代码定义了一个“bool”关键字:

def str2bool(v):
  #susendberg's function
  return v.lower() in ("yes", "true", "t", "1")
p = argparse.ArgumentParser()
p.register('type','bool',str2bool) # add type keyword to registries
p.add_argument('-b',type='bool')  # do not use 'type=bool'
# p.add_argument('-b',type=str2bool) # works just as well
p.parse_args('-b false'.split())
Namespace(b=False)

parser.register()没有记录,但也没有隐藏。大多数情况下,程序员不需要知道它,因为typeaction接受函数和类值。有很多 stackoverflow 示例为两者定义自定义值。


如果前面的讨论不明显,bool()这并不意味着“解析字符串”。摘自 Python 文档:

bool(x):使用标准真值测试程序将值转换为布尔值。

对比一下

int(x):将数字或字符串 x 转换为整数。

解决方案 8:

一种非常相似的方法是使用:

feature.add_argument('--feature',action='store_true')

如果你在命令中设置了参数 --feature

 command --feature

该参数将为 True,如果您未设置类型 --feature,则参数默认值始终为 False!

解决方案 9:

我正在寻找同样的问题,在我看来,最好的解决方案是:

def str2bool(v):
  return v.lower() in ("yes", "true", "t", "1")

并使用它将字符串解析为布尔值,如上所述。

解决方案 10:

简单又安全。

from ast import literal_eval

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

编辑有几个人评论说使用内置功能不安全eval。这在脚注中有所说明。但考虑到人们有时会从 SO 中复制粘贴,最好有更安全、更正确的答案。

解决方案 11:

这符合我所期望的一切:

add_boolean_argument(parser, 'foo', default=True)
parser.parse_args([])                   # Whatever the default was
parser.parse_args(['--foo'])            # True
parser.parse_args(['--nofoo'])          # False
parser.parse_args(['--foo=true'])       # True
parser.parse_args(['--foo=false'])      # False
parser.parse_args(['--foo', '--nofoo']) # Error

代码:

def _str_to_bool(s):
    """Convert string to bool (in argparse context)."""
    if s.lower() not in ['true', 'false']:
        raise ValueError('Need bool; got %r' % s)
    return {'true': True, 'false': False}[s.lower()]

def add_boolean_argument(parser, name, default=False):                                                                                               
    """Add a boolean argument to an ArgumentParser instance."""
    group = parser.add_mutually_exclusive_group()
    group.add_argument(
        '--' + name, nargs='?', default=default, const=True, type=_str_to_bool)
    group.add_argument('--no' + name, dest=name, action='store_false')

解决方案 12:

除了@mgilson所说的之外,还应该注意,还有一种ArgumentParser.add_mutually_exclusive_group(required=False)方法可以使执行这一点变得简单--flag,并且--no-flag不会同时使用。

解决方案 13:

更简单的方法是使用如下所示的方法。

parser.add_argument('--feature', type=lambda s: s.lower() in ['true', 't', 'yes', '1'])

解决方案 14:

这实际上已经过时了。对于 Python 3.7+,Argparse 现在支持布尔参数(搜索 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 之外的所有参数条目。如果您出于任何原因想要尝试更改这一点,您可以为此创建一个自定义错误类。

解决方案 15:

之前关注过 @akash-desarda 的优秀回答https://stackoverflow.com/a/59579733/315112后,决定使用strtoboolvia ,后来我决定直接lambda使用。strtobool

import argparse
from distutils import util
parser.add_argument('--feature', type=util.strtobool)

是的,您说得对,strtobool返回的是int,而不是bool。但除了和strtobool之外不会返回任何其他值,并且 python 会将它们无缝且一致地转换为值。0`1`bool

>>> 0 == False
True
>>> 0 == True
False
>>> 1 == False
False
>>> 1 == True
True

在收到错误的输入值时

python yours.py --feature wrong_value

argparse.Action 与strtobool相比lambda会产生稍微更清晰/易懂的错误消息:

yours.py: error: argument --feature: invalid strtobool value: 'wrong_value'

与此代码相比,

parser.add_argument('--feature', type=lambda x: bool(util.strtobool(x))

这将产生一个不太清晰的错误信息:

yours.py: error: argument --feature: invalid <lambda> value: 'wrong_value'

解决方案 16:

扩展 gerardw 的答案

parser.add_argument("--my_bool", type=bool)不起作用的原因bool("mystring")True对于任何非空字符串bool("False")来说都是如此True

你想要的是

我的程序.py

import argparse

parser = argparse.ArgumentParser(description="My parser")

parser.add_argument(
        "--my_bool",
        choices=["False", "True"],
        )

parsed_args = parser.parse_args()

my_bool = parsed_args.my_bool == "True"

print(my_bool)
$ python my_program.py --my_bool False
False

$ python my_program.py --my_bool True
True

$ python my_program.py --my_bool true
usage: my_program.py [-h] [--my_bool {False,True}]
my_program.py: error: argument --my_bool: invalid choice: 'true' (choose from 'False', 'True')

解决方案 17:

其实非常简单。不需要导入任何包。

记住这type=func意味着返回 func(x),像type=bool -> bool(x)这样:

parser.add_argument('--feature', default=False, type=lambda x: x == 'True')

现在我们知道了原理,你也可以将其扩展到type=lambda x: x.lower() not in ['false', 'no', '0', 'none', ...]

解决方案 18:

最简单的方法是使用选择

parser = argparse.ArgumentParser()
parser.add_argument('--my-flag',choices=('True','False'))

args = parser.parse_args()
flag = args.my_flag == 'True'
print(flag)

不传递 --my-flag 则结果为 False。如果您始终希望用户明确指定选择,则可以添加required=True选项。

解决方案 19:

理解argparse和布尔参数

当使用argparse处理布尔命令行参数时,指定 的type=bool行为可能与您预期的不同。无论您传递还是 ,type=bool参数始终会将提供的值评估为。True`True`False

例如:

parser.add_argument("--my_bool", type=bool, default=False)

当你运行时:

my_program --my_bool False

arg.my_bool将被设置为True,而不是False,因为任何非空字符串参数(包括“False”)都True被 Python 的bool()函数解释为 。

处理布尔标志的正确方法

要正确处理布尔标志,请使用action带有store_true或 的参数store_false。这样,​​标志的存在将值设置为True,而标志的不存在将值设置为False

例如:

parser.add_argument("--my_boolean_flag", action="store_true", help="Set this flag to enable feature X")
  • 如果--my_boolean_flag在命令行中提供了,arg.my_boolean_flag将是True

  • 如果--my_boolean_flag没有提供,arg.my_boolean_flag则为False

示例用法

为了清楚起见,这里有一个完整的例子:

import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("--my_boolean_flag", action="store_true"(argparse.BooleanOptionalAction), help="Enable the boolean flag")
    args = parser.parse_args()

    print(args.my_boolean_flag)
  • 运行my_program会输出False

  • 运行my_program --my_boolean_flag会输出True

解决方案 20:

我认为最规范的方式是:

parser.add_argument('--ensure', nargs='*', default=None)

ENSURE = config.ensure is None

解决方案 21:

快速而简单,但仅适用于参数 0 或 1:

parser.add_argument("mybool", default=True,type=lambda x: bool(int(x)))
myargs=parser.parse_args()
print(myargs.mybool)

从终端调用后,输出将为“False”:

python myscript.py 0

解决方案 22:

class FlagAction(argparse.Action):
    # From http://bugs.python.org/issue8538

    def __init__(self, option_strings, dest, default=None,
                 required=False, help=None, metavar=None,
                 positive_prefixes=['--'], negative_prefixes=['--no-']):
        self.positive_strings = set()
        self.negative_strings = set()
        for string in option_strings:
            assert re.match(r'--[A-z]+', string)
            suffix = string[2:]
            for positive_prefix in positive_prefixes:
                self.positive_strings.add(positive_prefix + suffix)
            for negative_prefix in negative_prefixes:
                self.negative_strings.add(negative_prefix + suffix)
        strings = list(self.positive_strings | self.negative_strings)
        super(FlagAction, self).__init__(option_strings=strings, dest=dest,
                                         nargs=0, const=None, default=default, type=bool, choices=None,
                                         required=required, help=help, metavar=metavar)

    def __call__(self, parser, namespace, values, option_string=None):
        if option_string in self.positive_strings:
            setattr(namespace, self.dest, True)
        else:
            setattr(namespace, self.dest, False)

解决方案 23:

出现此问题的原因是type=boolinargparse无法按预期工作。任何非空字符串(如"False"OR 1OR abcd123)都像在 Python 中一样进行评估True

选项 1:自定义函数

使用自定义函数明确处理TrueFalse值:

import argparse

def str2bool(value):
    if isinstance(value, bool):
        return value
    if value.lower() in {'true', 't', 'yes', '1'}:
        return True
    elif value.lower() in {'false', 'f', 'no', '0'}:
        return False
    else:
        raise argparse.ArgumentTypeError(f'Invalid boolean value: {value}')

parser = argparse.ArgumentParser(description="My parser")
parser.add_argument("--my_bool", type=str2bool, default=False, help="Boolean flag")
cmd_line = ["--my_bool", "False"]
parsed_args = parser.parse_args(cmd_line)

print(parsed_args.my_bool)  # Output: False

这将运行为

python my_program.py --my_bool True
# Output: True

python my_program.py --my_bool False
# Output: False

选项 2:使用store_truestore_false- 你会发现这更常见

parser = argparse.ArgumentParser(description="My parser")
parser.add_argument("--my_bool", action="store_true", help="Set flag to True")
parser.add_argument("--no_bool", action="store_false", dest="my_bool", help="Set flag to False")
cmd_line = ["--my_bool"]
parsed_args = parser.parse_args(cmd_line)

print(parsed_args.my_bool)  # Output: True

这将运行如下:

python my_program.py --my_bool
# Output: True

python my_program.py --no_bool
# Output: False

但不确定性能如何

解决方案 24:

转换值:

def __arg_to_bool__(arg):
    """__arg_to_bool__

        Convert string / int arg to bool
    :param arg: argument to be converted
    :type arg: str or int
    :return: converted arg
    :rtype: bool
    """
    str_true_values = (
        '1',
        'ENABLED',
        'ON',
        'TRUE',
        'YES',
    )
    str_false_values = (
        '0',
        'DISABLED',
        'OFF',
        'FALSE',
        'NO',
    )

    if isinstance(arg, str):
        arg = arg.upper()
        if arg in str_true_values:
            return True
        elif arg in str_false_values:
            return False

    if isinstance(arg, int):
        if arg == 1:
            return True
        elif arg == 0:
            return False

    if isinstance(arg, bool):
        return arg

    # if any other value not covered above, consider argument as False
    # or you could just raise and error
    return False

[...]


args = ap.parse_args()
my_arg = options.my_arg
my_arg = __arg_to_bool__(my_arg)

解决方案 25:

您可以创建一个 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)

然后action=BoolAction开始parser.add_argument()

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用