用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=booltype='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,但也没有隐藏。 大部分程序员不需要知道它,因为typeaction都是函数和类的值。 有很多的定义自定义值的两个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!