2014-11-02 4 views
2

С argparse Я хотел бы иметь возможность смешивать дополнительные параметры с несколькими позиционными параметрами, например, как svn позволяет:argparse необязательный параметр в позиционной

svn ls first/path -r 1000 second/path 

На данный момент, это официально не поддерживается Python (cf http://bugs.python.org/issue14191). Я написал это обходное решение, и теперь мне интересно, если a) есть лучший/более простой/более элегантный способ сделать это, и b) если кто-то может увидеть что-то в коде, которое может сломать его при определенных условиях:

#!/usr/bin/env python3               

import argparse as ap               

p = ap.ArgumentParser()               
p.add_argument('-v', action='store_true')          
p.add_argument('-l', action='store_true')          
p.add_argument('files', nargs='*', action='append')        
p.add_argument('remainder', nargs=ap.REMAINDER, help=ap.SUPPRESS)     

args = p.parse_args()                
while args.remainder != []:               
    args = p.parse_args(args.remainder, args)          

print(args) 
пример

Использование:

./test.py a b -v c d 

Выход:

Namespace(files=[['a', 'b'], ['c', 'd']], l=False, remainder=[], v=True) 
+0

Существует версия обходного пути в 14191, которую вы можете загрузить и добавить в свой код - без изменения вашего 'argparse'. Это может понадобиться вам, если вам нужно определить больше «позиций». – hpaulj

ответ

2

Вы можете использовать parse_known_args вместо включения remainder:

import argparse as ap               

p = ap.ArgumentParser()               
p.add_argument('-v', action='store_true')          
p.add_argument('-l', action='store_true')          
p.add_argument('files', nargs='*', action='append')        

args, unknown = p.parse_known_args() 
while unknown: 
    args, unknown = p.parse_known_args(unknown, args) 

print(args) 

дает

Namespace(files=[['a', 'b'], ['c', 'd']], l=False, v=True) 
0

Хотите files=[['a', 'b'], ['c', 'd']] или files=['a', 'b', 'c', 'd']? Другими словами, следует

./test.py a b -v c d 
./test.py a b -v c -l d 
./test.py -l a b -v c d 

дают разные files списки списков.

append с * Позиционный, как правило, не имеет смысла, поскольку вы не можете повторить позиционный аргумент. Но с этим рекурсивным приложением он работает. Но если важны подсписки, почему бы не использовать множественные позиционные аргументы.

С другой стороны, чтобы получить плоский список «файлов», вы можете сделать несколько вещей:

Вы можете придавить список после разбора (например args.files=list(itertools.chain(*args.files)))

Вы можете использовать p.add_argument('files', nargs='?', action='append'). Это итерации по каждой строке file.

./test.py a b -l c d -v e f 
Namespace(files=['a', 'b', 'c', 'd', 'e', 'f'], l=True, remainder=[], v=True) 

Вы могли бы повторить http://bugs.python.org/issue14191 патч, удалив позиционный из начального синтаксического анализа. В этом случае extras можно просто вставить в args.

Недостатком этого является то, что usage и help известно ничего о позиционном, не требуя пользовательского usage и/или description параметр. Ответ

usage = usage: %(prog)s [-h] [-v] [-l] [files [files ...]] 
description = 'files: may be given in any order' 
p = ap.ArgumentParser(usage=usage, description=description)        
p.add_argument('-v', action='store_true')          
p.add_argument('-l', action='store_true')          
args, extras = p.parse_known_args() 
args.files = extras 

unutbu в не сохраняет группировки.Они теряются в первый раз через:

Пространство имен (файлы = [['a', 'b'], ['c', 'd', 'e', ​​'f']], l = True, v = True)

Это может быть изменено, чтобы дать плоский список:

p = ap.ArgumentParser() 
p.add_argument('-v', action='store_true') 
p.add_argument('-l', action='store_true') 
p.add_argument('files', nargs='*') 

args, unknown = p.parse_known_args() 
args.files.extend(unknown) 

итерация не требуется, так как optionals обрабатываются в первый раз через. Все, что осталось в unknown, - files.

В сумме - чтобы сохранить группировки, ваше решение кажется лучшим.

Смежные вопросы