Python 使用 argparse 解析布尔值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15008758/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 13:05:00  来源:igfitidea点击:

Parsing boolean values with argparse

pythonbooleanargparsecommand-line-parsing

提问by SuperElectric

I would like to use argparse to parse boolean command-line arguments written as "--foo True" or "--foo False". For example:

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

my_program --my_boolean_flag False

However, the following test code does not do what I would like:

但是,下面的测试代码没有做我想要的:

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)

Sadly, parsed_args.my_boolevaluates to True. This is the case even when I change cmd_lineto be ["--my_bool", ""], which is surprising, since bool("")evalutates to False.

可悲的是,parsed_args.my_bool评估为True. 即使我更改cmd_line["--my_bool", ""],情况也是如此,这令人惊讶,因为bool("")评估为False

How can I get argparse to parse "False", "F", and their lower-case variants to be False?

我怎样才能让 argparse 解析"False","F"和它们的小写变体False

采纳答案by Maxim

Yet another solution using the previous suggestions, but with the "correct" parse error from argparse:

使用先前建议的另一个解决方案,但“正确”的解析错误来自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.')

This is very useful to make switches with default values; for instance

这对于使用默认值进行开关非常有用;例如

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

allows me to use:

允许我使用:

script --nice
script --nice <bool>

and still use a default value (specific to the user settings). One (indirectly related) downside with that approach is that the 'nargs' might catch a positional argument -- see this related questionand this argparse bug report.

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

回答by mgilson

I think a more canonical way to do this is via:

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

command --feature

and

command --no-feature

argparsesupports this version nicely:

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)


Of course, if you really want the --arg <True|False>version, you could pass ast.literal_evalas the "type", or a user defined function ...

当然,如果你真的想要--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?

回答by susundberg

I was looking for the same issue, and imho the pretty solution is :

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

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

and using that to parse the string to boolean as suggested above.

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

回答by hpaulj

There seems to be some confusion as to what type=booland type='bool'might mean. Should one (or both) mean 'run the function bool(), or 'return a boolean'? As it stands type='bool'means nothing. add_argumentgives a 'bool' is not callableerror, same as if you used type='foobar', or type='int'.

关于什么type=booltype='bool'可能意味着什么似乎有些混乱。一个(或两个)应该是“运行函数bool()”还是“返回一个布尔值”?就目前而言,type='bool'没有任何意义。 add_argument给出一个'bool' is not callable错误,就像你使用type='foobar', 或 一样type='int'

But argparsedoes have registry that lets you define keywords like this. It is mostly used for action, e.g. `action='store_true'. You can see the registered keywords with:

但是argparse确实有注册表可以让您定义这样的关键字。它主要用于action,例如`action='store_true'。您可以通过以下方式查看已注册的关键字:

parser._registries

which displays a dictionary

显示字典

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

There are lots of actions defined, but only one type, the default one, argparse.identity.

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

This code defines a 'bool' keyword:

此代码定义了一个 '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()is not documented, but also not hidden. For the most part the programmer does not need to know about it because typeand actiontake function and class values. There are lots of stackoverflow examples of defining custom values for both.

parser.register()没有记录,也没有隐藏。在大多数情况下,程序员并不需要了解它,因为typeaction取函数和类值。有很多为两者定义自定义值的 stackoverflow 示例。



In case it isn't obvious from the previous discussion, bool()does not mean 'parse a string'. From the Python documentation:

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

bool(x): Convert a value to a Boolean, using the standard truth testing procedure.

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

Contrast this with

将此与

int(x): Convert a number or string x to an integer.

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

回答by foo

In addition to what @mgilson said, it should be noted that there's also a ArgumentParser.add_mutually_exclusive_group(required=False)method that would make it trivial to enforce that --flagand --no-flagaren't used at the same time.

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

回答by Robert T. McGibbon

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)

回答by fnkr

I recommend mgilson's answer but with a mutually exclusive group
so that you cannot use --featureand --no-featureat the same time.

我推荐 mgilson 的答案,但有一个相互排斥的组,
这样你就不能同时使用--feature--no-feature

command --feature

and

command --no-feature

but not

但不是

command --feature --no-feature

Script:

脚本:

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)

You can then use this helper if you are going to set many of them:

如果您要设置其中许多,则可以使用此助手:

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')

回答by dl.meteo

A quite similar way is to use:

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

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

and if you set the argument --feature in your command

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

 command --feature

the argument will be True, if you do not set type --feature the arguments default is always False!

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

回答by Stumpy Joe Pete

This works for everything I expect it to:

这适用于我期望的一切:

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

The code:

编码:

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')

回答by Schaki

Here is another variation without extra row/s to set default values. The bool always have a value assigned so that it can be used in logical statements without pre-checks.

这是另一种没有额外行/秒来设置默认值的变体。bool 总是有一个赋值,这样它就可以在没有预检查的情况下用于逻辑语句。

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("Check that args.do_something=" + str(args.do_something) + " is always a bool")

回答by arunkumarreddy

A simpler way would be to use as below.

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

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