874

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

4

23 回答 23

1178

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

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', 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?
于 2013-02-21T17:40:24.810 回答
440

使用先前建议的另一种解决方案,但来自以下的“正确”解析错误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 错误报告

于 2017-04-11T23:45:28.497 回答
333

如果您想允许--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')
于 2015-07-10T17:52:29.647 回答
106

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

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.")
于 2016-05-24T11:16:24.247 回答
71

单线:

parser.add_argument('--is_debug', default=False, type=lambda x: (str(x).lower() == 'true'))
于 2017-10-26T09:44:45.383 回答
37

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.

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

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 转换为整数。

于 2013-10-07T19:45:21.573 回答
27

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

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

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

 command --feature

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

于 2016-03-16T09:35:00.850 回答
19

最简单最正确的方法是:

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。

于 2020-01-03T13:49:40.720 回答
18

我一直在寻找同样的问题,恕我直言,漂亮的解决方案是:

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

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

于 2013-10-07T14:20:38.340 回答
14

这适用于我期望的一切:

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')
于 2016-03-24T06:09:20.867 回答
13

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

于 2014-03-28T04:20:17.473 回答
12

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

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

编辑:如果您不信任输入,请不要使用eval.

于 2020-04-03T16:51:13.990 回答
11

这实际上已经过时了。对于 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 以外的所有条目。如果您想出于任何原因尝试更改它,您可以为此创建一个自定义错误类。

于 2021-08-20T20:22:47.640 回答
8

一种更简单的方法是如下使用。

parser.add_argument('--feature', type=lambda s: s.lower() in ['true', 't', 'yes', '1'])
于 2016-12-27T05:44:03.120 回答
5

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

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

是的,你是对的,strtobool返回的是一个int,而不是一个bool。但strtobool不会返回除0and之外的任何其他值,python 会将它们无缝且一致地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'
于 2021-05-19T10:48:08.400 回答
3

最简单的方法是使用选择

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选项。

于 2019-06-12T13:26:52.680 回答
3

作为对@Akash Desarda 答案的改进,您可以这样做

import argparse
from distutils.util import strtobool

parser = argparse.ArgumentParser()
parser.add_argument("--foo", 
    type=lambda x:bool(strtobool(x)),
    nargs='?', const=True, default=False)
args = parser.parse_args()
print(args.foo)

它支持python test.py --foo

(base) [costa@costa-pc code]$ python test.py
False
(base) [costa@costa-pc code]$ python test.py --foo 
True
(base) [costa@costa-pc code]$ python test.py --foo True
True
(base) [costa@costa-pc code]$ python test.py --foo False
False
于 2020-05-20T12:58:29.943 回答
2

我认为最规范的方式是:

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

ENSURE = config.ensure is None
于 2017-02-24T13:41:06.030 回答
1

快速简单,但仅适用于参数 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
于 2019-10-18T14:09:08.727 回答
0
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)
于 2014-10-28T21:00:19.290 回答
0

类似于@Akash,但这是我使用的另一种方法。它使用strthanlambda因为 pythonlambda总是给我一种外星人的感觉。

import argparse
from distutils.util import strtobool

parser = argparse.ArgumentParser()
parser.add_argument("--my_bool", type=str, default="False")
args = parser.parse_args()

if bool(strtobool(args.my_bool)) is True:
    print("OK")
于 2020-04-27T06:20:00.700 回答
0

只需执行以下操作,您就可以--test = True使用

python 文件名 --test

parser.add_argument("--test" , default=False ,help="test ?", dest='test', action='store_true')
于 2020-09-17T10:23:01.230 回答
0

转换值:

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)

于 2021-01-08T08:19:54.537 回答