Узнайте, был ли аргумент указан пользователем при использовании Python argparse

Допустим, у меня есть тест python с использованием argparse с несколькими аргументами:

  • IP-адрес (по умолчанию: 127.0.0.1)
  • enabled_features (по умолчанию: [A, B, C])

Иногда я хотел бы изменить значение enabled_features по умолчанию, скажем, на [A,B,C,D]:

  • в зависимости от чего-то, что мне нужно, чтобы узнать IP (так что это не может быть значением по умолчанию в том смысле, в котором argparse имеет значения по умолчанию)
  • только если пользователь не указал "enabled_features"... это то, что мне трудно узнать!

Итак, есть ли атрибут в классах argparse, который нужно знать после:

opts = parser.parse_args()

... что аргумент был фактически указан пользователем, т.е. что он использовал что-то вроде:

$ python my_test.py --enabled_features A B C

и не:

$ python my_test.py

Спасибо!


person Mathias    schedule 16.01.2014    source источник


Ответы (3)


opts содержит всю информацию, которую argparse может вам предоставить. Таким образом, вам нужно либо проверить какое-то значение по умолчанию (чаще всего None), либо отсутствие атрибута (если default=argparse.SUPPRESS).

Другой подход заключается в том, чтобы указать разумное default и не беспокоиться о том, указал ли пользователь те или иные значения во входных данных. Что важнее, что пользователь указал значения, или сами значения?

person hpaulj    schedule 16.01.2014
comment
Я признаю, что неявное изменение значения по умолчанию, как правило, плохая идея, а установка по умолчанию значения None делает его более явным. Однако во многих случаях идея изменить значение по умолчанию после синтаксического анализа была если не самой лучшей, то самой очевидной из возможных... - person Mathias; 20.01.2014
comment
Обратите внимание, что все значения не обязательно будут иметь значение по умолчанию None по умолчанию, если вы используете такие действия, как store_true. - person AdamC; 18.03.2016
comment
Значение по умолчанию store_true равно False, что также разумно. Неоднозначность возникает только в том случае, если командная строка может указать значение, которое проверяется так же, как значение по умолчанию. - person hpaulj; 18.03.2016
comment
Спасибо за упоминание argparse.SUPPRESS. - person ChrisP; 18.02.2017
comment
opts содержит всю информацию, которую argparse может вам предоставить. Это, в частности, не соответствует действительности. Это также непитоновское чувство. В питоне мы все взрослые люди по обоюдному согласию, и если вы достаточно постараетесь, вы сможете откопать почти любую информацию, которую захотите. - person lhuber; 06.07.2017
comment
parse_args хранит локальную запись о том, какие действия были просмотрены, но она теряется, когда метод возвращается. Метод не изменяет никакие атрибуты парсера. - person hpaulj; 06.07.2017

Что-то типа...

myopts = vars(opts)
if opts['enabled_features'] is None:
    #Set the default parameters as you please.

Позволит вам увидеть, указали ли они выбор в командной строке (при условии, что вы добавили аргумент в синтаксический анализатор).

person C.B.    schedule 16.01.2014
comment
Извините, похоже не работает, где бы я его ни ставил, так как в нашем случае opts['enabled_features'] содержит значение по умолчанию, а не None, если оно не было указано пользователем... - person Mathias; 20.01.2014
comment
Я думаю, он хотел сказать НЕ устанавливать значения по умолчанию в add_argument('enabled_features'), тогда вы можете проверить, что это None, и выполнить сложную логику в зависимости от других аргументов. - person nos; 20.06.2017

сам объект анализатора сохраняет некоторую полезную информацию, которую мы можем используйте, чтобы проверить значения по умолчанию, которые мы назначили при добавлении аргумента.

Пример скрипта parser_ex.py:

import argparse

def specified_nondefault(opts, parser, arg):
  """
  Checks whether an argument was specified to be something other than the 
  default value.

  ..Note: This doesn't actually check if the argument was specified, as it
          can be 'tricked' by the user specifying the default value.

  :param argparse.Namespace opts: Parsed arguments to check.
  :param argparse.Parser parser: The parser they were parsed with.
  :param str arg: The name of the argument in question.
  :return bool: Whether the current argument value differs from the default.
  """

  if getattr(opts, arg) == parser.get_default(arg):
    return False
  return True

parser = argparse.ArgumentParser()

parser.add_argument('enabled_features', nargs='*', default=['A', 'B', 'C', 'D'])

opts = parser.parse_args()

print specified_nondefault(opts, parser, 'enabled_features')

В таком случае:

>> parser_ex.py 'B' True

Потому что мы сделали что-то нестандартное. Пока

>> parser_ex.py 'A' 'B' 'C' 'D' False

а также

>> parser_ex.py False

Так как это просто ввод по умолчанию.

Обратите внимание, что, поскольку мы проверяем весь список, существует некоторое нежелательное поведение, когда порядок имеет значение и

>> parser_ex.py 'B' 'A' 'C' True

IMO, это проблема с объединением всех функций в один аргумент, но вы, безусловно, можете так или иначе обойти это, если вам это небезразлично.

Затем, если пользователь указал/не указал нестандартные enabled_features, вы можете изменить их на основе IP по желанию.

person lhuber    schedule 06.07.2017
comment
Вы проверяете значение opts на известное значение default. Вы не нашли никакой скрытой информации, созданной во время by parse_args()`. Этот метод не изменяет состояние парсера. - person hpaulj; 06.07.2017
comment
Да, именно этим я и занимаюсь. Моя цель состояла в том, чтобы показать, где найти значение по умолчанию, которое было создано при добавлении аргумента (вместо того, чтобы явно предполагать, что это None, как в ответе CB). Я никогда не утверждал, что информация скрыта, просто показывал, где она хранятся и связаны соответствующие документы. Я также не претендовал на изменение состояния самого парсера, и мне непонятно, зачем мне это нужно. - person lhuber; 06.07.2017
comment
Ага, я вижу, где я утверждал, что изменил состояние парсера. Весь код остался прежним, но описание было соответствующим образом изменено. - person lhuber; 06.07.2017