python argparse — либо оба необязательных аргумента, либо ни один

#python #python-3.x #parameter-passing #command-line-arguments #argparse

#python #аргументы командной строки #argparse

Вопрос:

У меня есть программа, которая использует имя и пароль по умолчанию. Я использую argparse, чтобы позволить пользователю указывать параметры командной строки, и я хотел бы разрешить пользователю предоставлять программе другое имя и пароль для использования. Итак, у меня есть следующее:

 parser.add_argument(
    '-n',
    '--name',
    help='the login name that you wish the program to use'
    )

parser.add_argument(
    '-p',
    '--password',
    help='the password to log in with.'
    )
 

Но нет никакого смысла указывать только имя или только пароль, но было бы разумно не указывать ни один. Я заметил, что argparse имеет возможность указать, что два аргумента являются взаимоисключающими. Но у меня есть два аргумента, которые должны отображаться вместе. Как мне добиться такого поведения? (Я нашел «группы аргументов», упомянутые в документах, но, похоже, они не решают мою проблему http://docs.python.org/2/library/argparse.html#argument-groups )

Комментарии:

1. И я предполагаю, что постобработка аргументов выходит за рамки вопроса?

2. Ни о чем не может быть и речи. Я просто хочу, чтобы argparse выполнил всю работу за меня и сообщил пользователю, что параметры должны отображаться вместе.

Ответ №1:

Я считаю, что лучший способ справиться с этим — это постобработать возвращенное пространство имен. Причина, по которой argparse это не поддерживается, заключается в том, что он анализирует аргументы по 1 за раз. Легко argparse проверить, было ли что-то уже проанализировано (именно поэтому взаимоисключающие аргументы работают), но нелегко увидеть, будет ли что-то проанализировано в будущем.

Простой:

 parser.add_argument('-n','--name',...,default=None)
parser.add_argument('-p','--password',...,default=None)
ns = parser.parse_args()

if len([x for x in (ns.name,ns.password) if x is not None]) == 1:
   parser.error('--name and --password must be given together')

name = ns.name if ns.name is not None else "default_name"
password = ns.password if ns.password is not None else "default_password"
 

похоже, этого будет достаточно.

Комментарии:

1. Это правильно, но ‘name = ns.name или «default_name» ‘ проще и, на мой взгляд, легче читать это’ns.name если ns.name is not None else …». Однако, как указывает mgilson в другом месте, если пользователь передает пустую строку для любого значения,пустая строка будет иметь значение false, и вместо предоставленной пустой строки будет использоваться значение по умолчанию.

2. sum(1 for x in (ns.name, ns.password) if x is not None) также работает вместо len([x for x in (ns.name,ns.password) if x is not None]) .

3. Этого было бы ns.name is None ^ ns.password is None недостаточно? : D

Ответ №2:

Я знаю, что это опоздало более чем на два года, но я нашел хороший и краткий способ сделать это:

 if bool(ns.username) ^ bool(ns.password):
    parser.error('--username and --password must be given together')
 

^ является оператором XOR в Python. Требовать оба аргумента, заданных в командной строке, по сути, является проверкой XOR.

Комментарии:

1. Разве это не должно быть XNOR?

2. @KaustubhKarkare XOR оценивается так, как True если бы указывались только имя пользователя или пароль. Выше описан случай сбоя в таком состоянии, так и должно быть XOR .

Ответ №3:

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

 default_name = "x"
default_pass = "y"
parser.add_argument(
    '-n',
    '--name',
    default=None,
    help='the login name that you wish the program to use'
    )

parser.add_argument(
    '-p',
    '--password',
    default=None,
    help='the password to log in with.'
    )
args = parser.parse_args()
if all(i is not None for i in [args.name, args.password]):
    name = args.name
    passwd = args.password
elif any(i is not None for i in [args.name, args.password]):
    parser.error("Both Name and Password are Required!")
else:
    name = default_name
    passwd = default_pass
 

Комментарии:

1. Будьте осторожны с этим. Что, если пользователь устанавливает свой пароль в пустую строку?

2. В качестве примечания вы всегда можете отредактировать свой удаленный ответ и отменить его удаление 🙂

3. Спасибо, это немного раздражает, когда он там висит.

4. Что ж, более того, если бы вы получили 10 голосов и галочку, вы могли бы получить значок просветленного 🙂

5. спасибо, и обновлено с проверкой на отсутствие, а не на ложность.