用argparseparsing布尔值
我想用argparse来parsing写成“–foo True”或“–foo False”的布尔命令行参数。 例如:
my_program --my_boolean_flag False
但是,下面的testing代码不会做我想要的:
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来parsing"False"
, "F"
和它们的小写variables是否为False
?
另一个解决scheme使用了以前的build议,但是从argparse
得到了“正确的”parsing错误:
def str2bool(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=NICE, help="Activate nice mode.")
允许我使用:
script --nice script --nice <bool>
仍然使用默认值(特定于用户设置)。 这种方法带来的一个(间接相关的)不利因素是,“nargs”可能会引起争议 – 看到这个相关的问题和这个粗糙的bug报告 。
我认为一个更经典的方法来做到这一点是通过:
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
作为“types”或用户定义的函数传递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?
我build议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)
似乎有什么type=bool
和type='bool'
可能意味着什么混淆。 如果一个(或两个)意味着'运行函数bool()
或'返回一个布尔值'? 就像这样, type='bool'
意味着什么。 add_argument
给出了一个'bool' is not callable
错误,就像你使用type='foobar'
或者type='int'
。
但是argparse
确实有registry,可以让你像这样定义关键字。 它主要用于action
,例如`action ='store_true'。 你可以看到注册的关键字:
parser._registries
显示一个字典
{'action': {None: argparse._StoreAction, 'append': argparse._AppendAction, 'append_const': argparse._AppendConstAction, ... 'type': {None: <function argparse.identity>}}
有很多定义的动作,但只有一个types,默认的, 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()
没有logging,但也没有隐藏。 大部分程序员不需要知道它,因为type
和action
都是函数和类的值。 有很多的定义自定义值的两个stackoverflow的例子。
如果从以前的讨论中不明显, bool()
并不意味着“parsingstring”。 从Python文档:
bool(x):使用标准真相testing程序将值转换为布尔值。
与此对比
int(x):将数字或stringx转换为整数。
我正在寻找同样的问题,imho漂亮的解决scheme是:
def str2bool(v): return v.lower() in ("yes", "true", "t", "1")
并使用它来parsingstring布尔如上build议。
除了@mgilson说的外,还应该注意的是,还有一个ArgumentParser.add_mutually_exclusive_group(required=False)
方法,它可以使强制执行这个方法变得微不足道--flag
和--no-flag
不会同时使用。
这是另外一个没有额外行的variables来设置默认值。 布尔值总是有一个赋值,这样它就可以在没有预先检查的情况下在逻辑语句中使用。
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 == True: print("Do something") else: print("Don't do something) print("Check that args.do_something=" + str(args.do_something) + " is always a bool")
这适用于我所期望的一切:
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')
更简单的方法是使用如下。
parser.add_argument('--feature', type=lambda s: s.lower() in ['true', 't', 'yes', '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'--[Az]+', 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)
我认为最经典的方法是:
parser.add_argument('--ensure', nargs='*', default=None) ENSURE = config.ensure is None
oneliner:
parser.add_argument('--is_debug', default=False, type=lambda x: (str(x).lower() == 'true'))
一个非常相似的方式是使用:
feature.add_argument('--feature',action='store_true')
如果你在你的命令中设置了参数–feature
command --feature
参数将为True,如果您不设置type –feature,则参数default始终为False!