在 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。

發生這種情況的原因是當在 add_argument() 中指定 type=xxx 時,參數被傳遞給 xxx()。

例如,如果 type=int,則參數將傳遞給 int();如果 type=float,則 float()。

type=bool 也是如此,這意味著參數將傳遞給 bool()。

通過 bool() 判斷

這個 bool() 是一個棘手的問題。

以下值被認為是錯誤的:

  • None
  • false
  • 數字類型為零。例如,以下值
    • 0
    • 0
    • 0j
  • 一個空的序列。例如
    • ()
    • []
  • 空映射。例如
    • {}

所有其他值都假定為真 – 因此許多類型的對象始終為真。除非另有說明,否則返回布爾結果的運算和內置函數總是返回 0 或 False 作為假值,返回 1 或 True 作為真值。

因此,所有傳遞給 bool() 的非空字符串,無論是“true”還是“false”,都將返回 true。只有空字符串才是假的。

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 沒有設置為true,則會加載為false,這是en 的默認值。

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

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

如果要設置默認為true,添加選項時為false,只需執行以下操作。
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 值,以 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'