在Python的argparse中处理布尔值时要小心。

商业

要在 Python 中处理命令行参数,可以使用 sys 模块的 argv 或 argparse 模块。

argparse模块允许灵活地处理命令行参数,但在处理布尔值(true, false)时必须注意。

这里提供了以下信息。

  • argparse,便于定义参数
  • 用argparse指定参数的类型(type)。
  • 不要指定 “bool “作为add_argument()的参数类型。
  • 通过bool()判断
  • 使用参数动作而不是参数类型。
  • 使用 strtobool()函数

argparse,便于定义参数

argparse模块使定义命令行参数变得容易。

argparse模块使创建用户友好的命令行界面变得容易。你定义你的程序需要哪些参数,argparse将找出如何从sys.argv中解析这些选项。argparse模块自动生成帮助和使用信息,如果用户为程序指定了无效的参数,则会引发错误。
argparse — Parser for command-line options, arguments and sub-commands — Python 3.10.0 Documentation

用argparse指定参数的类型(type)。

argparse的一个有用的功能是指定类型(type)。

例如,如果你指定一个整数(int)类型,它将自动把参数转换为int,同时对不是int的参数提出错误。

该类型由add_argument()的参数类型指定。

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('arg_int', type=int)

args = parser.parse_args()
print(args.arg_int)
print(type(args.arg_int))

从命令行运行这个文件。

$ python argparse_type_int.py 100
100
<type 'int'>

参数100被读作int。

如果使用一个非int值作为参数,将发生错误。

$ python argparse_type_int.py foo
usage: argparse_type_int.py [-h] arg_int
argparse_type_int.py: error: argument arg_int: invalid int value: 'foo'

$ python argparse_type_int.py 1.23
usage: argparse_type_int.py [-h] arg_int
argparse_type_int.py: error: argument arg_int: invalid int value: '1.23'

对于发挥意外的争论非常有用。

不要指定 “bool “作为add_argument()的参数类型。

需要注意的是,如果你指定bool作为add_argument()的参数类型,bool和int、float一样,不会像预期那样工作。

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('arg_bool', type=bool)

args = parser.parse_args()
print(args.arg_bool)
print(type(args.arg_bool))

从命令行运行这个文件。

$ python argparse_type_bool.py True
True
<type 'bool'>

如果使用true作为参数,它将被读作一个bool类型的true。这是预期的行为,但问题是下面这种情况。

$ python argparse_type_bool.py False
True
<type 'bool'>

$ python argparse_type_bool.py bar
True
<type 'bool'>

如果你使用false或任何其他字符串作为参数,它将被读取为true。

出现这种情况的原因是,当type=xxx在add_argument()中被指定时,参数被传递给xxx()。

例如,如果type=int,参数将被传递给int();如果type=float,则是float()。

type=bool的情况也是如此,这意味着该参数将被传递给bool()。

通过bool()判断

这个bool()是个棘手的问题。

以下数值被认为是假的。

  • None
  • false
  • 在数字类型中为零。例如,以下数值
    • 0
    • 0.0
    • 0j
  • 一个空的序列。比如说
    • ''
    • ()
    • []
  • 空的映射。比如说
    • {}

所有其他的值都假定为真–因此许多类型的对象总是真。返回布尔结果的操作和内置函数总是返回0或False作为假值,1或True作为真值,除非另有说明。

因此,所有传递给bool()的非空字符串,无论是 “真 “还是 “假”,都将返回真。只有空字符串将是假的。

print(bool('True'))
print(bool('False'))
print(bool('abc'))
# True
# True
# True

print(bool(''))
# False

当在add_argument()中设置type=bool时,该参数会被传递给bool()。因此,如上面的例子所示,如果false被用作参数,它将被bool()转换为字符串 “False “并被读作true。

使用参数动作而不是参数类型。

如果你想在argparse中使用布尔值,为参数动作指定'store_true'或'store_false'。

  • 'store_true'
  • 'store_false'

这些将是'store_const'的特殊版本,将分别存储True和False。此外,它们将分别把默认值设置为False和True,按照这个顺序。
argparse — Parser for command-line options, arguments and sub-commands — Python 3.10.0 Documentation

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--en', action='store_true')

args = parser.parse_args()
print(args.en)
print(type(args.en))

在这个例子中,给出了以下选项。
--en因此,如果en没有被设置为真,它将被加载为假,这是en的默认值。

$ python argparse_option_bool.py --en
True
<type 'bool'>

$ python argparse_option_bool.py
False
<type 'bool'>

如果你想把默认值设置为 “真”,而在添加选项时设置为 “假”,只需做以下工作。
action='store_false'

使用 strtobool()函数

如果你想使用位置参数而不是选项,你也可以使用strtobool()函数。

strtobool()是一个将字符串转换为真(1)或假(0)的函数。

将一个布尔型字符串转换为真(1)或假(0)。
真实值如下

  • y
  • yes
  • true
  • on
  • 1

虚假值如下。

  • n
  • no
  • f
  • false
  • off
  • 0

如果val不是上述任何一个,就会引发ValueError。

9. API Reference – strtobool() — Python 3.10.0 Documentation

它不区分大小写,因此,例如,你可以使用以下内容;任何其他字符串将导致错误。

  • 'TRUE'
  • 'True'
  • 'YES'
from distutils.util import strtobool

print(strtobool('true'))
print(strtobool('True'))
print(strtobool('TRUE'))
# 1
# 1
# 1

print(strtobool('t'))
print(strtobool('yes'))
print(strtobool('y'))
print(strtobool('on'))
print(strtobool('1'))
# 1
# 1
# 1
# 1
# 1

print(strtobool('false'))
print(strtobool('False'))
print(strtobool('FALSE'))
# 0
# 0
# 0

print(strtobool('f'))
print(strtobool('no'))
print(strtobool('n'))
print(strtobool('off'))
print(strtobool('0'))
# 0
# 0
# 0
# 0
# 0

# print(strtobool('abc'))
# ValueError: invalid truth value 'abc'

名字是strtobool(),但返回值不是bool,而是int(1或0)。

print(type(strtobool('true')))
# <class 'int'>

正如前面所写,当在argparse的add_argument()中指定type=xxx时,该参数将被传递给xxx()。因此,我们可以做以下事情。
type=strtobool

import argparse
from distutils.util import strtobool

parser = argparse.ArgumentParser()
parser.add_argument('arg_bool', type=strtobool)

args = parser.parse_args()
print(args.arg_bool)
print(type(args.arg_bool))

返回值不是bool类型,而是int类型1或0,但它可以以true或false作为参数读取真假值。

$ python argparse_type_strtobool.py true
1
<type 'int'>

$ python argparse_type_strtobool.py false
0
<type 'int'>

另外,如果参数不是预期的,将正确产生一个错误。

$ python argparse_type_strtobool.py bar
usage: argparse_type_strtobool.py [-h] arg_bool
argparse_type_strtobool.py: error: argument arg_bool: invalid strtobool value: 'bar'