Как с помощью модуля Python optparse создать параметр, который принимает переменное количество аргументов?

С помощью Perl Getopt::Long вы можете легко определить параметры командной строки, которые принимают переменное количество аргументов:

foo.pl --files a.txt             --verbose
foo.pl --files a.txt b.txt c.txt --verbose

Есть ли способ сделать это напрямую с помощью модуля Python optparse? Насколько я могу судить, атрибут опции nargs можно использовать для указания фиксированного числа аргументов опции, и я не видел других альтернатив в документации.


person FMc    schedule 22.06.2009    source источник
comment
Укажите имена файлов с помощью аргументов, а не с помощью опции: foo.pl a.txt b.txt c.txt --verbose в этом случае имена файлов будут помещены в аргументы.   -  person jfs    schedule 22.06.2009
comment
Если --files определяет входные данные, этот подход не рекомендуется.   -  person S.Lott    schedule 22.06.2009


Ответы (6)


Я считаю, что optparse не поддерживает то, что вам нужно (не напрямую - как вы заметили, вы можете это сделать, если готовы выполнить всю дополнительную работу обратного вызова!-). Вы также можете сделать это проще всего с помощью стороннего расширения argparse, которое поддерживает переменные числа. аргументов (а также добавляет несколько других полезных функций).

Этот URL документирует add_argument argparse — передача nargs='*' позволяет варианту ноль или более аргументов, '+' позволяет принимать один или более аргументов и т. д.

person Alex Martelli    schedule 22.06.2009
comment
Ага, но если вы еще не можете обновиться до версии 2.7 (выпущенной позавчера), сторонний пакет все равно находка!-) - person Alex Martelli; 06.07.2010

Мне потребовалось некоторое время, чтобы понять это, но вы можете использовать действие обратного вызова для своих опций, чтобы сделать это. Посмотрите, как я получаю произвольное количество аргументов для флага «--file» в этом примере.

from optparse import OptionParser,

def cb(option, opt_str, value, parser):
        args=[]
        for arg in parser.rargs:
                if arg[0] != "-":
                        args.append(arg)
                else:
                        del parser.rargs[:len(args)]
                        break
        if getattr(parser.values, option.dest):
                args.extend(getattr(parser.values, option.dest))
        setattr(parser.values, option.dest, args)

parser=OptionParser()
parser.add_option("-q", "--quiet",
        action="store_false", dest="verbose",
        help="be vewwy quiet (I'm hunting wabbits)")
parser.add_option("-f", "--filename",
        action="callback", callback=cb, dest="file")

(options, args) = parser.parse_args()

print options.file
print args

Единственным побочным эффектом является то, что вы получаете свои аргументы в списке вместо кортежа. Но это можно легко исправить, для моего конкретного случая использования список желателен.

person Dave Rawks    schedule 05.02.2010
comment
На самом деле я предпочитаю пример в документе python, как показано в ответе FMc: stackoverflow.com/a/1025230/422670 - person Stefano; 23.05.2012
comment
Они функционально эквивалентны, за исключением того, что пример кода также позволяет анализировать значения, такие как -1, как аргументы для флага, что, как я полагаю, является хорошей функцией для некоторых случаев использования. - person Dave Rawks; 25.05.2012
comment
действительно, он допускает отрицательные числа (мне также нравится, что это взято прямо из официальных документов :)) - person Stefano; 25.05.2012

Моя ошибка: только что нашел этот пример обратного вызова 6 .

person FMc    schedule 22.06.2009
comment
Это определенно лучший ответ на конкретный вопрос; argparse намного лучше, но вы не всегда можете легко его использовать: например. в команде управления Django. - person Stefano; 23.05.2012

Не лучше ли с этим?

foo.pl --files a.txt,b.txt,c.txt --verbose
person Peter Ericson    schedule 22.06.2009
comment
Нет. Определенно нет. Например, это запретит расширения оболочки, такие как foo.py *.txt. - person Constantinius; 04.07.2012
comment
Я не думаю, что он заслуживает -1, в некоторых случаях это может быть допустимым решением, например, список с плавающей запятой в ссылке на документацию выше. Может быть, вопросительный тон немного не тот (но откуда мне знать...). - person dhill; 07.12.2012
comment
@Constantinius - расширение оболочки не всегда желательно. Если вы имеете дело с большим количеством входных файлов, вы можете достичь произвольного ограничения длины командной строки (сделанного динамическим из-за того, что оно сжимается в зависимости от размера вашей среды), и в этом случае лучше использовать метод bsd_glob perl glob выполнить расширение после того, как вы получили аргументы. Я обычно предоставляю несколько шаблонов файлов/шаблонов в кавычках, разделенных пробелами. - person hepcat72; 19.05.2016

У меня недавно возникла эта проблема: я работал на Python 2.6 и нуждался в возможности принимать переменное количество аргументов. Я попытался использовать решение Дейва, но обнаружил, что оно не будет работать без явной установки nargs в 0.

def arg_list(option, opt_str, value, parser):
    args = set()
    for arg in parser.rargs:
        if arg[0] == '-':
            break
        args.add(arg)
        parser.rargs.pop(0)
    setattr(parser.values, option.dest, args)

parser=OptionParser()
parser.disable_interspersed_args()
parser.add_option("-f", "--filename", action="callback", callback=arg_list,
                  dest="file", nargs=0)

(options, args) = parser.parse_args()

Проблема заключалась в том, что по умолчанию предполагается, что новая опция, добавленная add_options, имеет nargs = 1, а когда nargs > 0, OptionParser будет извлекать элементы из rargs и присваивать им значение до того, как будут вызваны какие-либо обратные вызовы. Таким образом, для опций, которые не указывают nargs, rargs всегда будет выключен на единицу к моменту вызова вашего обратного вызова.

Этот обратный вызов можно использовать для любого количества опций, просто пусть callback_args будет вызываемой функцией вместо setattr.

person Jeremy Paige    schedule 10.06.2015
comment
у меня это работает с небольшим изменением: если arg[0] == '-': - person Maoz Zadok; 07.11.2016

Вот один из способов: взять строку генерации fileLst в виде строки, а затем использовать http://docs.python.org/2/library/glob.html, чтобы сделать расширение, тьфу, это может не работать без экранирования *

На самом деле есть способ получше: python myprog.py -V -l 1000 /home/dominic/radar/*.json ‹- Если это ваша командная строка

парсер, opts = parse_args()

inFileLst = парсер.largs

person dominic suciu    schedule 01.03.2013