跳转至

Python argparse 解析命令行参数为布尔值

在 Python 开发中,命令行参数解析是一个常见的需求,它允许我们以命令行的方式向程序传递参数,从而实现更灵活和可配置的程序设计。Python 提供了一个内置库 argparse,它简化了命令行参数解析的过程。

这篇帖子介绍过如何使用 argparse 解析命令行参数,本文将介绍如何指定命令行参数为布尔值类型。直接使用 type=bool 是无法实现的,而需要传入一个 callable 的对象,在其中编写将字符串转换为布尔值的逻辑。

image-20231122230439023

尝试指定 type=bool

首先我们尝试指定 type=bool

Python
import argparse

parser = argparse.ArgumentParser("test")
parser.add_argument("--yesorno", type=bool, default=True)

args = parser.parse_args()
yesorno = args.yesorno

print(type(yesorno))
print(yesorno)

在命令行中运行:

image-20231122225326154

可以看到,即使提供的参数为 False,但程序仍然解析为了 True。这是因为 argparse 会将我们提供的 False 当作是一个字符串,再对这个字符串进行判断是否为 True,而字符串 bool("False") 的结果是 True

image-20231122225600838

使用 type=lambda x: (str(x).lower() == 'true')

参考 Stackoverflow 的回答,我们可以对 type 传入一个 callable 的对象,在其中编写将字符串转换为布尔值的逻辑。

Python
import argparse

parser = argparse.ArgumentParser("test")
parser.add_argument(
    "--yesorno", type=lambda x: (str(x).lower() == "true"), default=True
)

args = parser.parse_args()
yesorno = args.yesorno

print(type(yesorno))
print(yesorno)

image-20231122225811749

考虑更全面的写法

有时用户并不只是提供 True 这样标准的写法,例如 yesyt 等等可能都代表真值含义。参考 Stackoverflow 的回答,我们可以定义更全面的判断逻辑:

Python
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.')

或者参考 Stackoverflow 的回答的评论区,可以使用内置的 distutils.util.strtobool,自动判断多种表达真值的字符串:

Python
import argparse
from distutils.util import strtobool

parser = argparse.ArgumentParser("test")
parser.add_argument("--yesorno", type=lambda x: bool(strtobool(str(x))), default=True)

args = parser.parse_args()
yesorno = args.yesorno

print(type(yesorno))
print(yesorno)

image-20231122230439023

distutils.util.strtobool 的实现
Python
def strtobool(val):
    """Convert a string representation of truth to true (1) or false (0).

    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.
    """
    val = val.lower()
    if val in ('y', 'yes', 't', 'true', 'on', '1'):
        return 1
    elif val in ('n', 'no', 'f', 'false', 'off', '0'):
        return 0
    else:
        raise ValueError("invalid truth value {!r}".format(val))

评论