Есть ли способ использовать Python argparse с nargs='*', выбором и значением по умолчанию?Python

Программы на Python
Ответить
Anonymous
 Есть ли способ использовать Python argparse с nargs='*', выбором и значением по умолчанию?

Сообщение Anonymous »

Мой вариант использования — несколько необязательных позиционных аргументов, взятых из ограниченного набора вариантов, со значением по умолчанию, которое представляет собой список, содержащий два из этих вариантов. Я не могу изменить интерфейс из-за проблем с обратной совместимостью. Мне также необходимо поддерживать совместимость с Python 3.4.
Вот мой код. Как видите, я хочу, чтобы по умолчанию использовался список из двух значений из набора вариантов.
parser = argparse.ArgumentParser()
parser.add_argument('tests', nargs='*', choices=['a', 'b', 'c', 'd'],
default=['a', 'd'])
args = parser.parse_args()
print(args.tests)

Все верно:
$ ./test.py a
['a']
$ ./test.py a d
['a', 'd']
$ ./test.py a e
usage: test.py [-h] [{a,b,c,d} ...]
test.py: error: argument tests: invalid choice: 'e' (choose from 'a', 'b', 'c', 'd')

Это неверно:
$ ./test.py
usage: test.py [-h] [{a,b,c,d} ...]
test.py: error: argument tests: invalid choice: ['a', 'd'] (choose from 'a', 'b', 'c', 'd')

Я нашел МНОГО подобных вопросов, но ни один из них не касался этого конкретного варианта использования. Самое многообещающее предложение, которое я нашел (в другом контексте), - это написать собственное действие и использовать его вместо вариантов: Это не идеально. Я надеюсь, что кто-нибудь подскажет мне вариант, который я пропустил.
Вот обходной путь, который я планирую использовать, если нет:
parser.add_argument('tests', nargs='*',
choices=['a', 'b', 'c', 'd', 'default'],
default='default')

Мне разрешено добавлять аргументы, если я поддерживаю обратную совместимость.
Спасибо!

Обновление: в итоге я выбрал настраиваемое действие. Я сопротивлялся, потому что это не похоже на вариант использования, который требует чего-то специального. Тем не менее, это более или менее похоже на предполагаемый вариант использования подкласса argparse.Action, и это делает намерение очень явным и дает самый чистый результат, ориентированный на пользователя, который я нашел.
class TestsArgAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
all_tests = ['a', 'b', 'c', 'd']
default_tests = ['a', 'd']

if not values:
setattr(namespace, self.dest, default_tests)
return

# If no argument is specified, the default gets passed as a
# string 'default' instead of as a list ['default']. Probably
# a bug in argparse. The below gives us a list.
if not isinstance(values, list):
values = [values]

tests = set(values)

# If 'all', is found, replace it with the tests it represents.
# For reasons of compatibility, 'all' does not actually include
# one of the tests (let's call it 'e'). So we can't just do
# tests = all_tests.
try:
tests.remove('all')
tests.update(set(all_tests))
except KeyError:
pass

# Same for 'default'
try:
tests.remove('default')
tests.update(set(default_tests))
except KeyError:
pass

setattr(namespace, self.dest, sorted(list(tests)))


Подробнее здесь: https://stackoverflow.com/questions/733 ... nd-default
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»