Python'un argparse'sinde aynı seçeneği birden çok kez kullanmak


85

Birden çok girdi kaynağını kabul eden ve her birine bir şeyler yapan bir betik yazmaya çalışıyorum. Bunun gibi bir şey

./my_script.py \
    -i input1_url input1_name input1_other_var \
    -i input2_url input2_name input2_other_var \
    -i input3_url input3_name
# notice inputX_other_var is optional

Ama bunu kullanarak nasıl yapacağımı tam olarak anlayamıyorum argparse. Her seçenek bayrağı yalnızca bir kez kullanılabilecek şekilde ayarlanmış gibi görünüyor. Tek bir seçenekle ( nargs='*'veya nargs='+') birden çok argümanı nasıl ilişkilendireceğimi biliyorum , ancak bu yine de -ibayrağı birden çok kez kullanmama izin vermiyor . Bunu başarmaya nasıl devam ederim?

Açıkça söylemek gerekirse, sonunda istediğim şey dizelerin listelerinin bir listesidir. Yani

[["input1_url", "input1_name", "input1_other"],
 ["input2_url", "input2_name", "input2_other"],
 ["input3_url", "input3_name"]]

Öyleyse neden çoklu giriş kaynağı argümanlarını bu tek seçenekle ilişkilendirmiyorsunuz?
TigerhawkT3

Çünkü çoklu giriş kaynaklarının her birinin birden çok dize argümanına sahip olması gerekir. Girdilerin her biri için -i bayrağını kullanmak zorunda kalacağım ve her girdi ardışık -i bayrakları arasındaki tüm dizeleri içerecektir. -İ ile girdileri belirttiğiniz ffmpeg gibi çalışmasını istiyorum
John Allard

Yanıtlar:


97

Burada, isteğe bağlı olarak tekrarlanan 2 bağımsız değişkeni işleyen bir ayrıştırıcı var metavar:

parser=argparse.ArgumentParser()
parser.add_argument('-i','--input',action='append',nargs=2,
    metavar=('url','name'),help='help:')

In [295]: parser.print_help()
usage: ipython2.7 [-h] [-i url name]

optional arguments:
  -h, --help            show this help message and exit
  -i url name, --input url name
                        help:

In [296]: parser.parse_args('-i one two -i three four'.split())
Out[296]: Namespace(input=[['one', 'two'], ['three', 'four']])

Bu, 2 or 3 argument durumla (bir süre önce böyle bir aralığı ele alacak bir Python hatası / sorunu için bir yama yazmış olsam da).

nargs=3Ve ile ayrı bir argüman tanımına ne dersiniz?metavar=('url','name','other') ?

Demet metavarda kullanılabilir nargs='+'ve nargs='*'; 2 dize [-u A [B ...]]veya olarak kullanılır [-u [A [B ...]]].


1
Vay güzel! Yardım işlevinin, çok parçalı seçeneğin tek tek bileşenlerinin neyi temsil ettiğini göstermesini seviyorum. Bunu kullanacağım!
John Allard

49

Bu çok basit; sadece ikisini de ekleyin action='append've nargs='*'(veya '+').

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', action='append', nargs='+')
args = parser.parse_args()

Sonra çalıştırdığınızda, alırsınız

In [32]: run test.py -i input1_url input1_name input1_other_var -i input2_url i
...: nput2_name input2_other_var -i input3_url input3_name

In [33]: args.i
Out[33]:
[['input1_url', 'input1_name', 'input1_other_var'],
 ['input2_url', 'input2_name', 'input2_other_var'],
 ['input3_url', 'input3_name']]

2
Teşekkürler, tam olarak ihtiyacım olan şey! : D Yan Not: Olası bir varsayılan türü listesi / dizi olması gerekiyor ya Argparse başarısız olur
Tarwin

22

-i3 bağımsız değişkeni kabul edecek ve appendeylemi kullanacak şekilde yapılandırılmalıdır .

>>> p = argparse.ArgumentParser()
>>> p.add_argument("-i", nargs=3, action='append')
_AppendAction(...)
>>> p.parse_args("-i a b c -i d e f -i g h i".split())
Namespace(i=[['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']])

İsteğe bağlı bir değeri işlemek için basit bir özel tür kullanmayı deneyebilirsiniz. Bu durumda, argümanı -ivirgülle ayrılmış tek bir dizedir ve bölme sayısı 2 ile sınırlıdır. Belirtilen en az iki değer olduğundan emin olmak için değerleri sonradan işlemeniz gerekir.

>>> p.add_argument("-i", type=lambda x: x.split(",", 2), action='append')
>>> print p.parse_args("-i a,b,c -i d,e -i g,h,i,j".split())
Namespace(i=[['a', 'b', 'c'], ['d', 'e'], ['g', 'h', 'i,j']])

Daha fazla kontrol için özel bir eylem tanımlayın. Bu, yerleşik olanı genişletir _AppendAction(tarafından kullanılır action='append'), ancak yalnızca verilen argümanların sayısı üzerinde bir aralık kontrolü yapar -i.

class TwoOrThree(argparse._AppendAction):
    def __call__(self, parser, namespace, values, option_string=None):
        if not (2 <= len(values) <= 3):
            raise argparse.ArgumentError(self, "%s takes 2 or 3 values, %d given" % (option_string, len(values)))
        super(TwoOrThree, self).__call__(parser, namespace, values, option_string)

p.add_argument("-i", nargs='+', action=TwoOrThree)

1
Parlak! Yardımın için teşekkürler.
John Allard

2
Bu tam olarak istediğinizi yapmıyor; Bunun inputX_other_varisteğe bağlı olduğunu kaçırdım .
chepner

Bu şekilde yorum yapmak için geri döndüm, senin yolun tüm değişkenleri gerektirir. Yine de doğru yönde!
John Allard

1
Tamam, isteğe bağlı 3. bağımsız değişkeni işlemek için birkaç seçenekle güncellendi.
chepner
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.