2009-06-22 8 views
11

Z Perl Getopt::Long można łatwo określić opcje wiersza polecenia, które mają zmienną liczbę argumentów:Z modułem optparse Pythona, jak utworzyć opcję, która pobiera zmienną liczbę argumentów?

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

Czy istnieje sposób, aby to zrobić bezpośrednio z modułem Pythona optparse? O ile mogę powiedzieć, atrybut opcji nargs może być użyty do określenia stałej liczby argumentów opcji i nie widziałem innych alternatyw w dokumentacji.

+1

Określ nazwy plików za pomocą argumentów, nie poprzez opcję: 'foo.pl a.txt b.txt c.txt --verbose' Nazwy plików będą umieszczane w argach w tym przypadku. – jfs

+0

Jeśli --file definiuje dane wejściowe, takie podejście nie jest zalecane. –

Odpowiedz

8

Wierzę, że optparse nie obsługuje tego, czego potrzebujesz (nie bezpośrednio - jak zauważyłeś, możesz to zrobić, jeśli chcesz wykonać dodatkową pracę wywołania zwrotnego!). Możesz także zrobić to najprościej z rozszerzeniem trzeciej strony argparse, które obsługuje zmienne liczby argumentów (a także dodaje kilka innych poręcznych bitów funkcji).

This URL dokumenty argparse „s add_argument - przechodzące nargs='*' opcja pozwala wziąć zero lub więcej argumentów, '+' pozwala trwać jeden lub więcej argumentów, itp

+4

'argparse' jest w Pythonie 2.7+ http://docs.python.org/library/argparse.html – jfs

+2

Tak, ale jeśli nie możesz jeszcze uaktualnić do wersji 2.7 (wydanej przedwczoraj), pakiet trzeciej strony jest nadal bóg z nieba! -) –

9

Mój błąd: właśnie znalazłem to Callback Example 6.

+4

To zdecydowanie najlepsza odpowiedź na dokładne pytanie; argparse jest o wiele lepszy, ale nie zawsze można go łatwo użyć: np. w poleceniu zarządzania Django. – Stefano

2

Czy nie lepiej z tym?

foo.pl --files a.txt,b.txt,c.txt --verbose 
+1

Nie. Zdecydowanie nie. Na przykład może to uniemożliwić rozwinięcia powłoki, takie jak 'foo.py * .txt'. – Constantinius

+0

Nie sądzę, że zasługuje na -1, może to być poprawne rozwiązanie w niektórych przypadkach, takie jak lista zmiennoprzecinkowa w powyższym odnośniku do dokumentacji. Może ton pytający jest trochę nietypowy (ale co ja wiem ...). – dhill

+0

@Constantinius - Rozszerzanie powłoki nie zawsze jest pożądane. Jeśli masz do czynienia z dużą liczbą plików wejściowych, możesz osiągnąć arbitralny limit długości linii poleceń (dynamiczny dzięki temu, że kurczy się w zależności od rozmiaru twojego środowiska), w takim przypadku lepiej użyć metody bsd_glob firmy perl glob zrobić ekspansję po otrzymaniu argumentów. Zwykle dostarczam wiele wzorów plików/globów w cudzysłowach, rozdzielanych spacjami. – hepcat72

20

Zajęło mi to trochę czasu, aby się dowiedzieć, ale można użyć akcji wywołania zwrotnego do opcji, aby to zrobić. Sprawdź, w jaki sposób pobieram dowolną liczbę argumentów do flagi "--file" w tym przykładzie.

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 

Jedynym skutkiem ubocznym jest uzyskanie argumentów na liście zamiast krotki. Ale można to łatwo naprawić, dla mojego konkretnego przypadku lista jest pożądana.

+0

Właściwie wolę przykład w dokumencie Pythona, jak pokazano w odpowiedzi FMc: http://stackoverflow.com/a/1025230/422670 – Stefano

+1

Te dwa są funkcjonalnie równoważne, z wyjątkiem kodu przykładowego, który pozwala również na takie wartości jak "-1". przetwarzane jako argumenty na flagę, co jest fajną funkcją, którą przypuszczam w niektórych przypadkach użycia. –

+0

Rzeczywiście, pozwala na liczby ujemne (lubię też, że pochodzi prosto z oficjalnych dokumentów :)) – Stefano

0

Oto jeden sposób: Weź generujący ciąg fileLst w postaci ciągu znaków, a następnie użyć http://docs.python.org/2/library/glob.html zrobić ekspansję ugh to nie może działać bez ucieczki *

Właściwie lepszy sposób: Pythona myprog.py -V -l 1000 /home/dominic/radar/*.json < - Jeśli jest to Twoja linia poleceń

parser, zdecyduje = parse_args()

inFileLst = parser.largs

1

Niedawno miałem ten problem osobiście: byłem na Pythonie 2.6 i potrzebowałem opcji, aby pobrać zmienną liczbę argumentów. Próbowałem użyć rozwiązanie Dave'a, ale okazało się, że nie będzie działać bez również wyraźnie określających 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() 

Problemem było to, że domyślnie zakłada się nowa opcja dodana przez add_options mieć nargs = 1 i gdy nargs> 0 OptionParser wyskoczy przedmioty z rargs i przypisze je do wartości przed wywołaniem wywołań zwrotnych. Tak więc, dla opcji, które nie określają nargs, rargs będzie zawsze wyłączony o jeden do czasu wywołania callback.

To wywołanie zwrotne może być używane dla dowolnej liczby opcji, po prostu wywołaj funkcję callback jako funkcję, która ma zostać wywołana zamiast setattr.

+0

ten działa dla mnie z małą zmianą: "if arg [0] == '-':" –

Powiązane problemy