我想使用 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
?
parser.add_argument('--feature', dest='feature', default=False, action='store_true')
的单行解释。此解决方案将确保您始终获得值为 True
或 False
的 bool
类型。 (此解决方案有一个约束:您的选项必须具有默认值。)
parser.add_argument('--feature', dest='feature', type=lambda x:bool(distutils.util.strtobool(x)))
的单行解释。使用该选项时,此解决方案将确保 bool
类型的值为 True
或 False
。如果不使用该选项,您将获得 None
。 (distutils.util.strtobool(x)
is from another stackoverflow question)
parser.add_argument('--my_bool', action='store_true', default=False)
这样的东西怎么样
我认为更规范的方法是通过:
command --feature
和
command --no-feature
argparse
很好地支持这个版本:
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”可能会捕捉到位置参数——参见this related question和this argparse bug report。
if args.nice:
,因为如果参数设置为 False,它将永远不会通过条件。如果这是正确的,那么最好从 str2bool
函数返回列表并将列表设置为 const
参数,例如 [True]
、[False]
。如果我错了,请纠正我
如果您想同时允许 --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')
add_argument
用 dest='feature'
调用。 set_defaults
与 feature=True
一起调用。理解?
--flag False
,部分 SO 答案应该是关于他们试图解决的问题,而不仅仅是关于如何。绝对没有理由做 --flag False
或 --other-flag True
然后使用一些自定义解析器将字符串转换为布尔值。action='store_true'
和 action='store_false'
是使用布尔标志的最佳方法
... can be “don’t do that”, but it should also include “try this instead”
(至少对我而言)意味着答案应该在适当的时候更深入。有时我们中的一些人发布问题可以从更好/最佳实践等方面的指导中受益。回答“如前所述”通常不会做到这一点。话虽如此,您对经常假设太多(或错误)的答案感到沮丧是完全有效的。
parser.set_defaults(feature=None)
替换最后一行
help=
条目,它应该放在哪里?在 add_mutually_exclusive_group()
通话中?在一个或两个 add_argument()
调用中?别的地方?
这是另一个没有额外行来设置默认值的变体。布尔值总是被分配的,因此它可以在逻辑语句中使用而无需事先检查:
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.")
required=True
否则您将始终获得 True arg。
python3 test.py --do-something False
以 error: unrecognized arguments: False
失败,因此它并没有真正回答问题。
单线:
parser.add_argument('--is_debug', default=False, type=lambda x: (str(x).lower() == 'true'))
type=lambda x: (str(x).lower() in ['true','1', 'yes'])
distutils.utils.strtobool
,例如 type=lambda x: bool(strtobool(str(x)))
。真值为 y、yes、t、true、on 和 1; false 值为 n、no、f、false、off 和 0。
对于 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()
没有记录,但也没有隐藏。在大多数情况下,程序员不需要知道它,因为 type
和 action
采用函数和类值。有很多为两者定义自定义值的 stackoverflow 示例。
如果从前面的讨论中不明显,bool()
并不意味着“解析字符串”。来自 Python 文档:
bool(x):使用标准真值测试程序将值转换为布尔值。
将此与
int(x):将数字或字符串 x 转换为整数。
一个非常相似的方法是使用:
feature.add_argument('--feature',action='store_true')
如果您在命令中设置参数 --feature
command --feature
参数将为 True,如果您未设置 type --feature 参数默认值始终为 False!
--feature False
最简单最正确的方法是:
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。
我一直在寻找同样的问题,恕我直言,漂亮的解决方案是:
def str2bool(v):
return v.lower() in ("yes", "true", "t", "1")
并使用它来将字符串解析为布尔值,如上所述。
distutils.util.strtobool(v)
。
distutils.util.strtobool
返回 1 或 0,而不是实际的布尔值。
这适用于我期望的一切:
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')
_str_to_bool(s)
以转换 s = s.lower()
一次,然后测试 if s not in {'true', 'false', '1', '0'}
,最后是 return s in {'true', '1'}
。
除了@mgilson 所说的之外,还应该注意,还有一个 ArgumentParser.add_mutually_exclusive_group(required=False)
方法可以轻松强制执行 --flag
和 --no-flag
不同时使用。
最简单的。它不灵活,但我更喜欢简单。
parser.add_argument('--boolean_flag',
help='This is a boolean flag.',
type=eval,
choices=[True, False],
default='True')
编辑:如果您不信任输入,请不要使用 eval
。
eval
是一个内置函数。 docs.python.org/3/library/functions.html#eval 这可以是其他更灵活的方法可以利用的任何一元函数。
ast.literal_eval
更安全。
这实际上已经过时了。对于 Python 3.7+,Argparse now supports boolean args(搜索 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 以外的所有条目。如果您想出于任何原因尝试更改它,您可以为此创建一个自定义错误类。
New in version 3.9
,我无法在 3.7 中从 argparse
导入 BooleanOptionalAction
...
action=argparse.BooleanOptionalAction
的工作方式。之前在 type
下,它警告不要使用 type=bool
、"The bool() function is not recommended as a type converter. All it does is convert empty strings to False and non-empty strings to True. This is usually not what is desired."
。
args = ap.parse_args(['--foo', 'False'])
返回 True (在我看来它不应该
一种更简单的方法是如下使用。
parser.add_argument('--feature', type=lambda s: s.lower() in ['true', 't', 'yes', '1'])
在之前遵循 @akash-desarda 的卓越答案 https://stackoverflow.com/a/59579733/315112 后,通过 lambda
使用 strtobool
,后来,我决定直接使用 strtobool
。
import argparse
from distutils import util
parser.add_argument('--feature', type=util.strtobool)
是的,您是对的,strtobool
返回的是 int
,而不是 bool
。但 strtobool
不会返回除 0
和 1
之外的任何其他值,python 会将它们无缝且一致地转换为 bool
值。
>>> 0 == False
True
>>> 0 == True
False
>>> 1 == False
False
>>> 1 == True
True
在收到错误的输入值时,例如
python yours.py --feature wrong_value
与 lambda
相比,带有 strtobool
的 argparse.Action 将产生更清晰/易于理解的错误消息:
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'
最简单的方法是使用选择:
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 选项。
作为对@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
我认为最规范的方式是:
parser.add_argument('--ensure', nargs='*', default=None)
ENSURE = config.ensure is None
快速简单,但仅适用于参数 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
parser.add_argument("mybool", default=True,type=lambda x: bool(int(x)), choices=['0','1'])
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)
类似于@Akash,但这是我使用的另一种方法。它使用 str
而不是 lambda
因为 python lambda
总是给我一种外星人的感觉。
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")
只需执行以下操作,您可以使用 --test = True
python 文件名 --test
parser.add_argument("--test" , default=False ,help="test ?", dest='test', action='store_true')
转换值:
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)
扩展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')
我找到了将参数的默认值存储为 False 的好方法,当它出现在命令行参数中时,它的值应该为 true。
当您希望参数为真时的 cmd 命令:python main.py --csv
当你想要你的论点应该是假的时候:python main.py
import argparse
from ast import parse
import sys
parser = argparse.ArgumentParser(description='')
parser.add_argument('--csv', action='store_true', default = False
,help='read from csv')
args = parser.parse_args()
if args.csv:
print('reading from csv')
False
。
type=bool
应该开箱即用(考虑位置参数!)。即使您另外指定choices=[False,True]
,您最终也会将“False”和“True”都视为 True(由于从字符串转换为布尔值?)。 Maybe related issuebool()
函数应该做什么,或者 argparse 在type=fn
中应该接受什么?所有argparse
检查是fn
是可调用的。它期望fn
接受一个字符串参数,并返回一个值。fn
的行为是程序员的责任,而不是argparse's
。