Будьте осторожны при работе с булевыми значениями в argparse Python

Бизнес

Для обработки аргументов командной строки в Python используйте модули argv или argparse модуля sys.

Модуль argparse позволяет гибко работать с аргументами командной строки, но при работе с булевыми значениями (true, false) необходимо соблюдать осторожность.

Здесь представлена следующая информация.

  • argparse для простого определения аргументов
  • Укажите тип аргумента (тип) с помощью argparse
  • Не указывайте «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

Полезной функцией argparse является указание типа (type).

Например, если вы укажете тип integer (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.

Если в качестве аргумента используется неинтовое значение, произойдет ошибка.

$ 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, как и int и float, не будут работать так, как ожидается, если вы укажете bool в качестве типа аргумента в add_argument().

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, он будет прочитан как true типа bool. Это ожидаемое поведение, но проблема заключается в следующем случае.

$ 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(), будь то '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() — это функция, которая преобразует строку в true (1) или false (0).

Преобразует булеву строку в true (1) или false (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'>

Как было написано ранее, когда в add_argument() argparse указан 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'
Copied title and URL