问题:用argparse解析布尔值
我想使用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
什么?
I would like to use argparse to parse boolean command-line arguments written as “–foo True” or “–foo False”. For example:
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_bool
evaluates to True
. This is the case even when I change cmd_line
to be ["--my_bool", ""]
, which is surprising, since bool("")
evalutates to False
.
How can I get argparse to parse "False"
, "F"
, and their lower-case variants to be False
?
回答 0
另一个解决方案使用了先前的建议,但存在来自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>
并仍使用默认值(特定于用户设置)。这种方法的一个(间接相关的)缺点是“水罐”可能会引起位置争执-请参阅此相关问题和此argparse错误报告。
Yet another solution using the previous suggestions, but with the “correct” parse error from 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 question and this argparse bug report.
回答 1
我认为更规范的方法是通过:
command --feature
和
command --no-feature
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)
当然,如果您确实需要--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?
I think a more canonical way to do this is via:
command --feature
and
command --no-feature
argparse
supports this version nicely:
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_eval
as the “type”, or a user defined function …
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
我建议mgilson的答案,但有互相排斥的群体
,这样就可以不使用--feature
,并--no-feature
在同一时间。
command --feature
和
command --no-feature
但不是
command --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')
I recommend mgilson’s answer but with a mutually exclusive group
so that you cannot use --feature
and --no-feature
at the same time.
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')
回答 3
这是另一种变体,无需额外的行来设置默认值。布尔值始终分配有一个值,以便可以在逻辑语句中使用它而无需预先检查。
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")
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.
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")
回答 4
单线:
parser.add_argument('--is_debug', default=False, type=lambda x: (str(x).lower() == 'true'))
oneliner:
parser.add_argument('--is_debug', default=False, type=lambda x: (str(x).lower() == 'true'))
回答 5
关于什么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()
没有记录,但也没有隐藏。在大多数情况下,程序员并不需要了解它,因为type
和action
取函数和类值。有很多为这两者定义自定义值的stackoverflow示例。
万一从前面的讨论中看bool()
不出来,就不意味着“解析字符串”。从Python文档中:
bool(x):使用标准真值测试过程将值转换为布尔值。
与之对比
int(x):将数字或字符串x转换为整数。
There seems to be some confusion as to what type=bool
and 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_argument
gives a 'bool' is not callable
error, same as if you used type='foobar'
, or type='int'
.
But argparse
does 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:
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
.
This code defines a ‘bool’ keyword:
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 type
and action
take function and class values. There are lots of stackoverflow examples of defining custom values for both.
In case it isn’t obvious from the previous discussion, bool()
does not mean ‘parse a string’. From the Python documentation:
bool(x): Convert a value to a Boolean, using the standard truth testing procedure.
Contrast this with
int(x): Convert a number or string x to an integer.
回答 6
我一直在寻找相同的问题,恕我直言,漂亮的解决方案是:
def str2bool(v):
return v.lower() in ("yes", "true", "t", "1")
并按照上面的建议使用它来将字符串解析为布尔值。
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.
回答 7
一个非常类似的方法是使用:
feature.add_argument('--feature',action='store_true')
如果您在命令中设置了参数–feature
command --feature
如果未设置type –feature,则参数将为True,参数默认始终为False!
A quite similar way is to use:
feature.add_argument('--feature',action='store_true')
and if you set the argument –feature in your command
command --feature
the argument will be True, if you do not set type –feature the arguments default is always False!
回答 8
回答 9
这适用于我期望的所有功能:
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')
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')
回答 10
一种更简单的方法是按以下方式使用。
parser.add_argument('--feature', type=lambda s: s.lower() in ['true', 't', 'yes', '1'])
A simpler way would be to use as below.
parser.add_argument('--feature', type=lambda s: s.lower() in ['true', 't', 'yes', '1'])
回答 11
最简单 它不灵活,但我更喜欢简单。
parser.add_argument('--boolean_flag',
help='This is a boolean flag.',
type=eval,
choices=[True, False],
default='True')
编辑:如果您不信任输入,请不要使用eval
。
Simplest. It’s not flexible, but I prefer simplicity.
parser.add_argument('--boolean_flag',
help='This is a boolean flag.',
type=eval,
choices=[True, False],
default='True')
EDIT: If you don’t trust the input, don’t use eval
.
回答 12
最简单的方法是使用选择:
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。该要求=真,如果你总是希望用户显式地指定一个选择的选项可以添加。
Simplest way would be to use choices:
parser = argparse.ArgumentParser()
parser.add_argument('--my-flag',choices=('True','False'))
args = parser.parse_args()
flag = args.my_flag == 'True'
print(flag)
Not passing –my-flag evaluates to False. The required=True option could be added if you always want the user to explicitly specify a choice.
回答 13
我认为最典型的方法是:
parser.add_argument('--ensure', nargs='*', default=None)
ENSURE = config.ensure is None
I think the most canonical way will be:
parser.add_argument('--ensure', nargs='*', default=None)
ENSURE = config.ensure is None
回答 14
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)
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)
回答 15
最简单,最正确的方法是
from distutils import util
arser.add_argument('--feature', dest='feature', type=lambda x:bool(distutils.util.strtobool(x)))
请注意,True值为y,y,t,true,on和1;false值是n,no,f,false,off和0。如果val是其他值,则引发ValueError。
Simplest & most correct way is
from distutils import util
arser.add_argument('--feature', dest='feature', type=lambda x:bool(distutils.util.strtobool(x)))
Do note that True values are y, yes, t, true, on and 1;
false values are n, no, f, false, off and 0. Raises ValueError if val is anything else.
回答 16
快速简便,但仅适用于参数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
Quick and easy, but only for arguments 0 or 1:
parser.add_argument("mybool", default=True,type=lambda x: bool(int(x)))
myargs=parser.parse_args()
print(myargs.mybool)
The output will be “False” after calling from terminal:
python myscript.py 0
回答 17
类似于@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")
Similar to @Akash but here is another approach that I’ve used. It uses str
than lambda
because python lambda
always gives me an alien-feelings.
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")
回答 18
为了改善@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
As an improvement to @Akash Desarda ‘s answer, you could do
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)
And it supports 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