Парсинг булевых значений с помощью 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)
К сожалению, значение parsed_args.my_bool
оказывается равным True
. Это происходит даже при изменении cmd_line
на ["--my_bool", ""]
, что удивительно, поскольку bool("")
должно возвращать False
.
Как мне заставить argparse
правильно парсить значения "False", "F" и их аналоги в нижнем регистре как False
?
5 ответ(ов)
Если вы хотите одновременно разрешить --feature
и --no-feature
(последний имеет приоритет)
Это позволит пользователям создать алиас командной строки с --feature
, который можно будет переопределить с помощью --no-feature
.
Python 3.9 и выше
parser.add_argument('--feature', default=True, action=argparse.BooleanOptionalAction)
Python 3.8 и ниже
Я рекомендую ответ mgilson:
parser.add_argument('--feature', dest='feature', action='store_true')
parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)
Если вы НЕ хотите разрешать одновременно --feature
и --no-feature
Вы можете использовать группу взаимно исключающих аргументов:
feature_parser = parser.add_mutually_exclusive_group(required=False)
feature_parser.add_argument('--feature', dest='feature', action='store_true')
feature_parser.add_argument('--no-feature', dest='feature', action='store_false')
parser.set_defaults(feature=True)
Вы можете использовать этот вспомогательный метод, если вам нужно установить много таких аргументов:
def add_bool_arg(parser, name, default=False):
group = parser.add_mutually_exclusive_group(required=False)
group.add_argument('--' + name, dest=name, action='store_true')
group.add_argument('--no-' + name, dest=name, action='store_false')
parser.set_defaults(**{name:default})
add_bool_arg(parser, 'useful-feature')
add_bool_arg(parser, 'even-more-useful-feature')
Вот еще одна вариация, которая не требует дополнительных строк для установки значений по умолчанию. Булевое значение всегда присваивается, чтобы его можно было использовать в логических операциях без предварительной проверки:
import argparse
parser = argparse.ArgumentParser(description="Разбор булевого значения")
parser.add_argument("--do-something", default=False, action="store_true",
help="Флаг для выполнения действий")
args = parser.parse_args()
if args.do_something:
print("Выполняем действие")
else:
print("Действие не выполняется")
print(f"Проверьте, что args.do_something={args.do_something} всегда является булевым значением.")
Таким образом, параметр --do-something
будет равен True
, если он указан в командной строке, и False
в противном случае, обеспечивая корректное булевое значение.
Самый простой и правильный способ сделать это:
from distutils.util import strtobool
parser.add_argument('--feature', dest='feature',
type=lambda x: bool(strtobool(x)))
Обратите внимание, что истинные значения — это y
, yes
, t
, true
, on
и 1
; ложные значения — это n
, no
, f
, false
, off
и 0
. Если значение не соответствует ни одному из этих вариантов, будет вызвано исключение ValueError
.
Вы можете использовать следующий однострочник для добавления аргумента --is_debug
, который будет интерпретировать строку 'true' как True
, а все остальные значения как False
:
parser.add_argument('--is_debug', default=False, type=lambda x: x.lower() == 'true')
Существует некоторая путаница относительно того, что именно означает type=bool
и type='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
return v.lower() in ("yes", "true", "t", "1")
p = argparse.ArgumentParser()
p.register('type','bool',str2bool) # добавляем ключевое слово в реестр
p.add_argument('-b',type='bool') # не используйте 'type=bool'
# p.add_argument('-b',type=str2bool) # работает так же хорошо
p.parse_args('-b false'.split())
Namespace(b=False)
Метод parser.register()
не задокументирован, но и не скрыт. В большинстве случаев программисту не нужно о нем беспокоиться, поскольку параметры type
и action
могут принимать значения функций и классов. В интернете можно найти множество примеров на StackOverflow о том, как определить свои собственные значения для обоих параметров.
Если это не очевидно из предыдущего обсуждения, bool()
не означает "разобрать строку". Согласно документации Python:
bool(x): Преобразует значение в логическое, используя стандартную процедуру проверки истинности.
Контрастируйте это с:
int(x): Преобразует число или строку x в целое число.
"Как использовать необязательные позиционные аргументы в Argparse?"
Преобразование строки в булево значение в Python
Как проверить, пуста ли строка в Python?
Неоднозначное значение истинности Series. Используйте a.empty, a.bool(), a.item(), a.any() или a.all()
Как отсортировать список/кортеж списков/кортежей по элементу на заданном индексе