Аргумент Python argparse: аргумент командной строки, который может быть либо именованным, либо позиционным

Я пытаюсь создать программу Python, которая использует модуль argparse для анализа параметров командной строки.

Я хочу сделать необязательный аргумент, который можно назвать или позиционным. Например, я хочу, чтобы myScript --username=batman выполнял то же самое, что и myScript batman. Я также хочу myScript без имени пользователя. Это возможно? Если да, как это можно сделать?

Я пробовал разные вещи, похожие на код ниже, без каких-либо успехов.

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-u", "--user-name", default="admin")
group.add_argument("user-name", default="admin")
args = parser.parse_args()

EDIT:. Вышеприведенный код генерирует исключение, говорящее ValueError: mutually exclusive arguments must be optional.

Я использую Python 2.7.2 для OS X 10.8.4.

РЕДАКТИРОВАТЬ. Я попробовал предложение Габриэля Якобсона, но во всех случаях я не мог нормально работать.

Я пробовал это:

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-u", "--user-name", default="admin", nargs="?")
group.add_argument("user_name", default="admin", nargs="?")
args = parser.parse_args()
print(args)

и запуск myScript batman будет печатать Namespace(user_name='batman'), но myScript -u batman и myScript --user-name=batman будут печатать Namespace(user_name='admin').

Я попытался изменить имя user-name на user_name в 1-й строке add_argument, что иногда приводило к как batman, так и admin в пространстве имен или ошибке, в зависимости от того, как я запускал программу.

Я попытался изменить имя user_name на user-name во второй строке add_argument, но это напечатает либо Namespace(user-name='batman', user_name='admin'), либо Namespace(user-name='admin', user_name='batman'), в зависимости от того, как я запускал программу.

Ответ 1

Как работает ArgumentParser, он всегда проверяет любые возвращающие позиционные аргументы после того, как он проанализировал необязательные аргументы. Поэтому, если у вас есть позиционный аргумент с тем же именем, что и необязательный аргумент, и он нигде не отображается в командной строке, он гарантированно переопределяет необязательный аргумент (либо со значением по умолчанию, либо по умолчанию).

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

Тем не менее, мое предлагаемое решение состоит в том, чтобы дать условному аргументу другое имя.

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('-u','--username')
group.add_argument('static_username',nargs='?',default='admin')

Затем при синтаксическом анализе вы используете необязательное имя пользователя, если оно присутствует, в противном случае отпадает в позиционное имя static_username.

results = parser.parse_args()
username = results.username or results.static_username

Я понимаю, что это не особенно опрятное решение, но я не думаю, что любой из ответов будет.

Ответ 2

Вот решение, которое, я думаю, делает все, что вы хотите:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-u", "--user-name", default="admin")
    # Gather all extra args into a list named "args.extra"
    parser.add_argument("extra", nargs='*')
    args = parser.parse_args()
    # Set args.user_name to first extra arg if it is not given and len(args.extra) > 0
    if args.user_name == parser.get_default("user_name") and args.extra:
        args.user_name = args.extra.pop(0)
    print args

Если вы запустите myScript -u batman или myScript --user-name=batman, args.user_name установлено значение 'batman'. Если вы выполняете myScript batman, args.user_name снова устанавливается на "batman". И, наконец, если вы просто выполняете myScript, args.user_name устанавливается в 'admin'.

Кроме того, в качестве дополнительного бонуса теперь у вас есть все дополнительные аргументы, которые были переданы в script, хранящиеся в args.extra. Надеюсь, это поможет.

Ответ 3

Попробуйте использовать параметр "nargs" метода add_argument. Таким образом, это работает для меня. Теперь вы можете добавить имя пользователя дважды, поэтому вам нужно проверить его и поднять ошибку, если хотите.

import argparse
if __name__ == '__main__':
   parser = argparse.ArgumentParser()
   parser.add_argument("-u", "--user-name", default="admin")
   parser.add_argument("user_name", default="admin", nargs="?")
   args = parser.parse_args()
   print(args)