boolean - 使用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)

时间:

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

 
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 ua == 'TRUE'[:len(ua)]:
 return True
 elif ua == 'FALSE'[:len(ua)]:
 return False
 else:
 pass #error condition maybe?

对于 type=booltype='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() 没有文档化,但也没有隐藏。 对于大多数部分来说,程序员不需要了解它,因为 typeaction take函数和类值。 有许多定义两个自定义值的stackoverflow示例。


如果在前面的讨论中不明显,bool() 并不意味着'分析字符串'。 从 python 文档中:

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

这里对比

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

我有同样的问题,但是我认为最好的解决方法是:


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

除了 @mgilson 说的,应该注意到还有一个 ArgumentParser.add_mutually_exclusive_group(required=False) 方法,这使得强制 --flag--no-flag 不同时使用变得微不足道。


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)

...