Я пытаюсь проанализировать командную строку в Python, который похож на следующее:
$ ./command -o option1 arg1 -o option2 arg2 arg3
Другими словами, команда берет неограниченное количество аргументов, и каждому аргументу можно дополнительно предшествовать с -o
опция, которая имеет отношение конкретно к тому аргументу. Я думаю, что это называют "префиксной нотацией".
В Оболочке Bourne я сделал бы что-то как следующее:
while test -n "$1"
do
if test "$1" = '-o'
then
option="$2"
shift 2
fi
# Work with $1 (the argument) and $option (the option)
# ...
shift
done
При оглядывании в учебных руководствах по Bash и т.д. это, кажется, принятая идиома, таким образом, я предполагаю, что Bash оптимизирован для работы с параметрами командной строки этого пути.
Пытаясь реализовать этот шаблон в Python, мое первое предположение должно было использовать pop()
, поскольку это - в основном операция стека. Но я предполагаю, что это не будет работать также над Python потому что список аргументов в sys.argv
находится в неправильном порядке и должен был бы быть обработан как очередь (т.е. поп слева). Я считал, что списки не оптимизированы для использования в качестве очередей в Python.
Так, мои идеи: преобразовать argv
к a collections.deque
и используйте popleft()
, реверс argv
использование reverse()
и используйте pop()
, или возможно просто работа с самими международными индексами списка.
Кто-либо знает о лучшем способе сделать это, иначе какая из моих идей была бы наиболее успешной практикой в Python?
p = argparse.ArgumentParser()
p.add_argument('-o', action='append')
for i in range(1, 4): p.add_argument('arg%d' % i)
args = p.parse_args('-o option1 arg1 -o option2 arg2 arg3'.split())
print args
# -> Namespace(arg1='arg1', arg2='arg2', arg3='arg3', o=['option1', 'option2'])
Не нужно изобретать велосипед: модуль getopt
предназначен именно для этого. Если это вам не подходит, попробуйте модуль optparse
, который более гибкий, но более сложный.
Вы можете сделать
argv.pop(0)
, который снимает первый элемент и возвращает его. Хотя, вероятно, это неэффективно. Может быть. Я не уверен, как argv
реализован под капотом. (Опять же, если эффективность , что важна, почему вы используете Python?)
Однако более питоническим решением было бы перебирать список без выталкивания элементов. Примерно так:
o_flag = False
for a in argv:
if a == '-o':
o_flag = True
continue
# do whatever
o_flag = False
Также я думаю, что заслуживает упоминания модуль optparse
; он довольно стандартен для обработки опций и аргументов в программах Python, хотя может оказаться излишним для этой задачи, поскольку у вас уже есть несколько совершенно функциональных решений.
Что-то вроде:
for arg in sys.argv[1:]:
# do something with arg
должно вам подойти. Если вы не ожидаете чрезвычайно большого количества аргументов, я бы выбрал самый простой код (и не слишком беспокоился о производительности). Argv [1:] игнорирует это первое значение argv, которое будет именем сценария.