2014-10-09 7 views
1

Возможно ли создать набор необязательных аргументов, которые связаны и повторяемы?Argparse, handle repeatable set items

Предположим, у меня есть три аргумента -a, -b, -c, которые образуют набор, -a требуется, но -b и -c являются необязательными. (Обновлено)

Я хотел бы указать несколько наборов из них.

Script.py -a 1 -b 2 -c 3 -a 4 -c 6 -a 7 -b 8 -a 10 

Это будет анализироваться в виде списка Словаря следующим

[ 
    {"a":1, "b":2, "c":3}, 
    {"a":4, "c":6}, 
    {"a":7, "b":8}, 
    {"a":10} 
] 
+0

Как вы собираетесь указать установить границы в командной строке? использование нескольких пространств - это визуальная справка, но когда ваша оболочка анализирует команду для выполнения, несколько пробелов не помогут. Таким образом, ваше приложение Python просто получит: -a 1 -b 2 -c 3 -a 4 -c 6 -b 8 -a 10'. Как вы теперь определяете наборы? Является ли допустимым предположение о том, что элементы каждого набора сортируются, поэтому вы знаете, что достигли другого набора, потому что раньше вы _c_, и теперь вы достигли _a_? – farzad

+0

Пространства были просто для того, чтобы четко показать возможное взаимодействие. Я согласен, что нет хорошего способа разбить их на множества без необходимого аргумента, спасибо, что, указав это, я должен был упомянуть, что -a - необходимый аргумент, это позволяет нам идентифицировать границы набора. Я думал просто использовать список для каждого аргумента и zip их как кортежи, но это будет некорректно, если отсутствуют некоторые необязательные аргументы. – user3043805

ответ

2

Способ сделать аргументы повторяемым является использование '' на добавление типа действий:

import argparse 
parser = argparse.ArgumentParser() 
parser.add_argument('-a', action='append') 
parser.add_argument('-b', action='append') 
parser.add_argument('-c', action='append') 
argv = '-a 1 -b 2 -c 3 -a 4 -c 6 -a 7 -b 8 -a 10' 
args = parser.parse_args(argv.split()) 
print args 

производит:

Namespace(a=['1', '4', '7', '10'], b=['2', '8'], c=['3', '6']) 

К сожалению, он теряет некоторую информацию. Невозможно связать «4» с «6» вместо «8».

Если вы используете «-», чтобы отделить блоки аргументов, то это итеративный анализатор может сделать работу:

parser = argparse.ArgumentParser() 
# SUPPRESS keeps the default None out of the namespace 
parser.add_argument('-a', type=int, default=argparse.SUPPRESS, required=True) 
parser.add_argument('-b', type=int, default=argparse.SUPPRESS) 
parser.add_argument('-c', type=int, default=argparse.SUPPRESS) 
argv = '-a 1 -b 2 -c 3 -- -a 4 -c 6 -- -a 7 -b 8 -- -a 10' 

arglist = [] 
rest = argv.split() 
while rest: 
    args,rest = parser.parse_known_args(rest) 
    rest = rest[1:] # remove the 1st '--' 
    print args 
    arglist.append(vars(args)) 
print arglist 

продуцирующие:

Namespace(a=1, b=2, c=3) 
Namespace(a=4, c=6) 
Namespace(a=7, b=8) 
Namespace(a=10) 

[{'a': 1, 'c': 3, 'b': 2}, 
{'a': 4, 'c': 6}, 
{'a': 7, 'b': 8}, 
{'a': 10}] 

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


Или адаптации итератор Farzad в:

def by_sets(iterator, start): 
    set = [] 
    for val in iterator: 
     if set and val == start: 
      yield set 
      set = [val] 
     else: 
      set.append(val) 
    yield set 

argv = '-a 1 -b 2 -c 3 -a 4 -c 6 -a 7 -b 8 -a 10' 
# print list(by_sets(argv.split(), '-a')) 
# [['-a', '1', '-b', '2', '-c', '3'], ['-a', '4', '-c', '6'],... ['-a', '10']] 

arglist = [] 
for aset in by_sets(argv.split(), '-a'): 
    arglist.append(vars(parser.parse_args(aset))) 
print arglist 

производит:

[{'a': 1, 'c': 3, 'b': 2}, {'a': 4, 'c': 6}, {'a': 7, 'b': 8}, {'a': 10}] 

Цикл также может быть записана в виде понимания:

[vars(parser.parse_args(aset)) for aset in by_sets(argv.split(), '-a')] 
+0

Отлично, спасибо, принимая решение hpaulj, поскольку вопрос был специфичным для argparse., хотя farzad предоставил полезные комментарии и код. Спасибо вам обоим – user3043805

1

Мы могли бы перебрать аргументы командной строки и добавьте их по одному множеству, если мы дошли до «-a» который знаменует начало другого набора, мы создадим новый набор. Этот пример кода не проверяет неверный ввод пользователя.

import sys 

def get_pairs(iterator, start): 
    sets = [] 
    for val in iterator: 
     if val == start: 
      sets.append({}) 
     sets[-1][val] = next(iterator) 
    return sets 

print get_pairs(iter(sys.argv[1:]), '-a') 
Смежные вопросы