Bir listeyi argparse ile komut satırı bağımsız değişkeni olarak nasıl iletebilirim?


443

Bir komut satırı programına argüman olarak bir liste geçirmeye çalışıyorum. Bir var mı argparseseçenek olarak bir liste geçmek seçeneği?

parser.add_argument('-l', '--list',
                      type=list, action='store',
                      dest='list',
                      help='<Required> Set flag',
                      required=True)

Script aşağıdaki gibi adlandırılır

python test.py -l "265340 268738 270774 270817"

Yanıtlar:


880

TL; DR

Kullan nargsseçeneğini veya 'append'ayarını action(eğer kullanıcı arayüzü davranmasını istiyorum nasıl bağlı olarak) seçeneği.

nargs

parser.add_argument('-l','--list', nargs='+', help='<Required> Set flag', required=True)
# Use like:
# python arg.py -l 1234 2345 3456 4567

nargs='+'1 veya daha fazla argüman nargs='*'alır, sıfır veya daha fazla alır.

ekleme

parser.add_argument('-l','--list', action='append', help='<Required> Set flag', required=True)
# Use like:
# python arg.py -l 1234 -l 2345 -l 3456 -l 4567

İle appendsize liste oluşturmak için seçenek defalarca sağlarlar.

Kullanmayın type=list!!! - Muhtemelen kullanmak istediğiniz olacak hiçbir engel yoktur type=listile argparse. Hiç.


Birinin bunu yapmaya çalışabileceği bazı farklı yollara ve sonuçlara daha ayrıntılı olarak bakalım.

import argparse

parser = argparse.ArgumentParser()

# By default it will fail with multiple arguments.
parser.add_argument('--default')

# Telling the type to be a list will also fail for multiple arguments,
# but give incorrect results for a single argument.
parser.add_argument('--list-type', type=list)

# This will allow you to provide multiple arguments, but you will get
# a list of lists which is not desired.
parser.add_argument('--list-type-nargs', type=list, nargs='+')

# This is the correct way to handle accepting multiple arguments.
# '+' == 1 or more.
# '*' == 0 or more.
# '?' == 0 or 1.
# An int is an explicit number of arguments to accept.
parser.add_argument('--nargs', nargs='+')

# To make the input integers
parser.add_argument('--nargs-int-type', nargs='+', type=int)

# An alternate way to accept multiple inputs, but you must
# provide the flag once per input. Of course, you can use
# type=int here if you want.
parser.add_argument('--append-action', action='append')

# To show the results of the given option to screen.
for _, value in parser.parse_args()._get_kwargs():
    if value is not None:
        print(value)

Bekleyebileceğiniz çıktı:

$ python arg.py --default 1234 2345 3456 4567
...
arg.py: error: unrecognized arguments: 2345 3456 4567

$ python arg.py --list-type 1234 2345 3456 4567
...
arg.py: error: unrecognized arguments: 2345 3456 4567

$ # Quotes won't help here... 
$ python arg.py --list-type "1234 2345 3456 4567"
['1', '2', '3', '4', ' ', '2', '3', '4', '5', ' ', '3', '4', '5', '6', ' ', '4', '5', '6', '7']

$ python arg.py --list-type-nargs 1234 2345 3456 4567
[['1', '2', '3', '4'], ['2', '3', '4', '5'], ['3', '4', '5', '6'], ['4', '5', '6', '7']]

$ python arg.py --nargs 1234 2345 3456 4567
['1234', '2345', '3456', '4567']

$ python arg.py --nargs-int-type 1234 2345 3456 4567
[1234, 2345, 3456, 4567]

$ # Negative numbers are handled perfectly fine out of the box.
$ python arg.py --nargs-int-type -1234 2345 -3456 4567
[-1234, 2345, -3456, 4567]

$ python arg.py --append-action 1234 --append-action 2345 --append-action 3456 --append-action 4567
['1234', '2345', '3456', '4567']

Paketler :

  • nargsVeya kullanınaction='append'
    • nargskullanıcı perspektifinden daha açık olabilir, ancak konumsal argümanların olması mantıksız olabilir, çünkü argparseneyin konumsal bir argüman olması gerektiğini ve neye ait olduğunu söyleyemem nargs; konumsal argümanlarınız varsa action='append', daha iyi bir seçim olabilir.
    • Yukarıdaki tek doğrunun nargsverilir '*', '+'ya da '?'. Bir tamsayı (örneğin 4) sağlarsanız, seçeneklerle nargsve konum bağımsız değişkenleriyle karıştırmada sorun olmaz, çünkü argparseseçenek için tam olarak kaç değer beklendiğini bilecektir.
  • Komut satırında tırnak kullanmayın 1
  • type=listBir liste listesi döndüreceği için kullanmayın
    • Bunun nedeni, başlık altında, seçtiğiniz her bir bağımsız değişkeni zorlamak argparseiçin değerini kullanmasıdır; tüm bağımsız değişkenlerin toplamını değil.typetype
    • Sen kullanabilirsiniz type=int(ya da herneyse) ints bir listesini almak (veya her neyse) için

1 : Genel olarak demek istemiyorum .. Yani bir listeyi geçmek içinargparse tırnak kullanmak istediğiniz şey değildir.


3
Dizelerin listesi ne olacak? Bu, birden çok dize bağımsız değişkenini ("naber", "bir şey" ve "başka") şuna benzer bir liste listesine dönüştürür: [['w', 'a', 's', 's', 'u' , 'p'], ['s', 'o', 'm', 'e', ​​'t', 'h', 'i', 'n', 'g'], ['e', ' l ',' s ',' e ']]
rd108

3
@ rd108 Görüyorum ki, type=listseçeneği kullandığınızdan eminim . Bunu kullanma. Bu, bir dizeyi bir listeye ve dolayısıyla liste listelerine dönüştürür.
SethMMorton

1
@Dror typeParametreyi başka bir nesneye ayarlamadığınız sürece, tüm girdilerin dizeler olduğu varsayılır . Varsayılan olarak bu yöntem bir dize listesi döndürür.
SethMMorton

1
--seçenekler ve konumsal argümanları bölebilir. prog --opt1 par1 ... -- posp1 posp2 ...
0andriy

1
konumsal argümanlar varsa kasıtsız olabilir, çünkü argparse neyin konumsal bir argüman olması gerektiğini ve nabızlara neyin ait olduğunu söyleyemez . --önceki yorumumda gösterildiği gibi bunu anlamaya yardımcı olur. IOW kullanıcı sarf malzemeleri ve --ardından tüm konumsal argümanlar.
0andriy

83

Komut dosyasında daha sonra ayrıştırdığım sınırlandırılmış bir dizeyi geçirmeyi tercih ederim. Bunun nedenleri; Liste herhangi bir tür olabilir intveya str, bazen kullanarak nargsçoklu isteğe bağlı bağımsız değişkenler ve pozisyonel argümanlar varsa sorunlarla gitmem.

parser = ArgumentParser()
parser.add_argument('-l', '--list', help='delimited list input', type=str)
args = parser.parse_args()
my_list = [int(item) for item in args.list.split(',')]

Sonra,

python test.py -l "265340,268738,270774,270817" [other arguments]

veya,

python test.py -l 265340,268738,270774,270817 [other arguments]

iyi çalışır. Sınırlayıcı da bir soru olabilir ve bu da sorudaki örnekte olduğu gibi bağımsız değişken değeri etrafında tırnak işaretleri uygular.


57
typeArgümanı lambda s: [int(time) for item in s.split(',')]sonradan işleme yerine olarak ayarlayabilirsiniz args.list.
chepner

13
@ chepner, evet kesinlikle haklısın ve daha pitonik olurdu - sadece küçük bir yazım hatası: int(time)olmalı int(item). Örneğim, basit bir işlemden ziyade birçok şeyi kontrol ettiğim tipik olarak yaptığımın basitleştirilmiş bir versiyonuydu. Ama sadece soruyu cevaplamak için, ben de yolunuzu daha zarif buluyorum ..
dojuba

1
bu cevap en pitonik gibi görünüyor
Quetzalcoatl

1
@Chepner tarafından yapılan yorum bazı ciddi ninja skillz +1
Briford Wylie

1
lambda items: list(csv.reader([items]))[0]standardına csv kütüphanesinden yorumun değiştirilmiş bir versiyonu @chepner (: ref kimse keyfi CSV girişi endişe için cevap dan @adamk ).
Kevin

19

Buna ek olarak nargs, choiceslisteyi önceden biliyorsanız de kullanmak isteyebilirsiniz :

>>> parser = argparse.ArgumentParser(prog='game.py')
>>> parser.add_argument('move', choices=['rock', 'paper', 'scissors'])
>>> parser.parse_args(['rock'])
Namespace(move='rock')
>>> parser.parse_args(['fire'])
usage: game.py [-h] {rock,paper,scissors}
game.py: error: argument move: invalid choice: 'fire' (choose from 'rock',
'paper', 'scissors')

10

Argparse'ın add_argument yönteminde nargs parametresini kullanma

Bir add_argument parametresi olarak nargs = ' ' kullanıyorum. Özellikle herhangi bir açık argüman geçirmiyorsam varsayılanları seçme seçeneğine nargs = ' ' kullandım

Örnek olarak bir kod snippet'i eklemek:

Örnek: temp_args1.py

Lütfen Dikkat: Aşağıdaki örnek kod python3 ile yazılmıştır. Print deyimi biçimini değiştirerek, python2'de çalışabilir

#!/usr/local/bin/python3.6

from argparse import ArgumentParser

description = 'testing for passing multiple arguments and to get list of args'
parser = ArgumentParser(description=description)
parser.add_argument('-i', '--item', action='store', dest='alist',
                    type=str, nargs='*', default=['item1', 'item2', 'item3'],
                    help="Examples: -i item1 item2, -i item3")
opts = parser.parse_args()

print("List of items: {}".format(opts.alist))

Not: Listede depolanan birden fazla dize argümanı topluyorum - opts.alist Tamsayıların listesini istiyorsanız, parser.add_argument üzerindeki type parametresini int olarak değiştirin

Yürütme Sonucu:

python3.6 temp_agrs1.py -i item5 item6 item7
List of items: ['item5', 'item6', 'item7']

python3.6 temp_agrs1.py -i item10
List of items: ['item10']

python3.6 temp_agrs1.py
List of items: ['item1', 'item2', 'item3']

1
@Py_minion Bir listeyi bağımsız değişken olarak kullanmanın ve çıktıyı liste olarak almanın bir yolu var mı? temp_args1.py -i [item5 ,item6, item7]ve çıktının bir liste olarak
çıkmasını sağlayın

@Moondra Evet. sorduğuna sevindim. `` parser.add_argument ('- o', '--options', action = 'store', dest = 'opt_list', type = str, nargs = '*', varsayılan = sample_list, help = "Veritabanı dizesi Boşluk ile ayrılmış Örnekler: \ -o seçenek1 seçenek2, -o seçenek3 ")` `Burada 'örnek_listesi' varsayılan seçeneklerle tür listesidir. Örn: sample_list = [seçenek4, seçenek5]
Py_minion

1
@Py_minion Teşekkürler. Bugün daha sonra test edeceğim.
Moondra

Bunu kullandım, bu argümanlardan liste oluşturmayı geçmek için çok yararlıdır.
siby

5

Tek bir anahtarın birden fazla parametre almasını istiyorsanız, bunu kullanın nargs='+'. '-L' örneğiniz aslında tamsayılar alıyorsa:

a = argparse.ArgumentParser()
a.add_argument(
    '-l', '--list',  # either of this switches
    nargs='+',       # one or more parameters to this switch
    type=int,        # /parameters/ are ints
    dest='list',     # store in 'list'.
    default=[],      # since we're not specifying required.
)

print a.parse_args("-l 123 234 345 456".split(' '))
print a.parse_args("-l 123 -l=234 -l345 --list 456".split(' '))

üretir

Namespace(list=[123, 234, 345, 456])
Namespace(list=[456])  # Attention!

Aynı bağımsız değişkeni birden çok kez belirtirseniz, varsayılan eylem ( 'store') varolan verilerin yerine geçer.

Alternatif, appendeylemi kullanmaktır :

a = argparse.ArgumentParser()
a.add_argument(
    '-l', '--list',  # either of this switches
    type=int,        # /parameters/ are ints
    dest='list',     # store in 'list'.
    default=[],      # since we're not specifying required.
    action='append', # add to the list instead of replacing it
)

print a.parse_args("-l 123 -l=234 -l345 --list 456".split(' '))

Hangi üretir

Namespace(list=[123, 234, 345, 456])

Veya virgülle ayrılmış değerleri ayrıştırmak için özel bir işleyici / eylem yazabilirsiniz.

-l 123,234,345 -l 456

5

In add_argument(), typeyalnızca dize alan ve seçenek değeri döndüren çağrılabilir bir nesnedir.

import ast

def arg_as_list(s):                                                            
    v = ast.literal_eval(s)                                                    
    if type(v) is not list:                                                    
        raise argparse.ArgumentTypeError("Argument \"%s\" is not a list" % (s))
    return v                                                                   


def foo():
    parser.add_argument("--list", type=arg_as_list, default=[],
                        help="List of values")

Bu aşağıdakilere izin verecektir:

$ ./tool --list "[1,2,3,4]"

Dizeleri geçmek gerekiyorsa, bu yöntemin komut satırında uygun şekilde alıntı yapmasını gerektirdiğini unutmayın. Bir kullanıcı bunu beklenmedik bulabilir. Sadece tamsayıları ayrıştırmak iyi olur.
SethMMorton

1

İç listelerin farklı tür ve uzunluklara sahip olduğu bir iç içe listeniz varsa ve türü korumak istiyorsanız, ör.

[[1, 2], ["foo", "bar"], [3.14, "baz", 20]]

o zaman önerdiği çözümü kullanabilirsiniz sam-mason @ için bu soruya aşağıda gösterilen:

from argparse import ArgumentParser
import json

parser = ArgumentParser()
parser.add_argument('-l', type=json.loads)
parser.parse_args(['-l', '[[1,2],["foo","bar"],[3.14,"baz",20]]'])

hangi verir:

Namespace(l=[[1, 2], ['foo', 'bar'], [3.14, 'baz', 20]])

0

Birden fazla liste, tamsayı değerleri ve dizeler geçirerek işlemek istiyorum.

Yardımcı link => Pashhon'a bir Bash değişkeni nasıl iletilir?

def main(args):
    my_args = []
    for arg in args:
        if arg.startswith("[") and arg.endswith("]"):
            arg = arg.replace("[", "").replace("]", "")
            my_args.append(arg.split(","))
        else:
            my_args.append(arg)

    print(my_args)


if __name__ == "__main__":
    import sys
    main(sys.argv[1:])

Düzen önemli değil. Bir listeyi geçmek istiyorsanız, aralarında olduğu gibi yapın "["ve "]virgül kullanarak ayırın.

Sonra,

python test.py my_string 3 "[1,2]" "[3,4,5]"

Output => ['my_string', '3', ['1', '2'], ['3', '4', '5']], my_argsdeğişken sırasıyla bağımsız değişkenleri içerir.


0

Bence en şık çözüm, Chepner tarafından da belirtildiği gibi, lambda fonksiyonunu "tip" e geçirmektir. Buna ek olarak, listenizdeki sınırlayıcının ne olacağını önceden bilmiyorsanız, re.split öğesine birden fazla sınırlayıcı da iletebilirsiniz:

# python3 test.py -l "abc xyz, 123"

import re
import argparse

parser = argparse.ArgumentParser(description='Process a list.')
parser.add_argument('-l', '--list',
                    type=lambda s: re.split(' |, ', s),
                    required=True,
                    help='comma or space delimited list of characters')

args = parser.parse_args()
print(args.list)


# Output: ['abc', 'xyz', '123']

-lÖrnek çağrıda mı demek istediniz ? Nereden -ngeldi?
Anthony

Ayrıca, çözüm Python 3.8.2'de benim için çalışmıyor. İşte kod: parser.add_argument('-l', '--list', type = lambda s: re.split('[ ,;]', s)). İşte girdidir: script.py -l abc xyz, abc\nxyz. Son olarak, sonuç:script.py: error: unrecognized arguments: xyz, abcnxyz
Anthony

Örneğimi çalışacak şekilde değiştirin :)
Nebulastic
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.