Komut satırı bağımsız değişkenlerini ayrıştırmanın en iyi yolu nedir? [kapalı]


251

Ne var en kolay , tersest ve en esnek Python komut satırı argümanları ayrıştırma yöntemi veya kütüphane?

Yanıtlar:


183

Bu cevap, optparseeski Python sürümleri için hangisinin uygun olduğunu göstermektedir . Python 2.7 ve üstü için yer argparsedeğiştirir optparse. Daha fazla bilgi için bu cevaba bakınız .

Diğer insanların işaret ettiği gibi, getopt üzerinde optparse ile gitmek daha iyidir. getopt, standart getopt (3) C kütüphanesi işlevlerinin neredeyse bire bir eşleşmesidir ve kullanımı çok kolay değildir.

optparse, biraz daha ayrıntılı olsa da, daha iyi yapılandırılmış ve daha sonra genişletilmesi daha kolaydır.

Ayrıştırıcıya bir seçenek eklemek için tipik bir satır:

parser.add_option('-q', '--query',
            action="store", dest="query",
            help="query string", default="spam")

Kendisi için hemen hemen konuşur; işlem zamanında -q veya --query seçeneklerini seçenek olarak kabul eder, bağımsız değişkeni sorgu adı verilen bir öznitelikte saklar ve belirtmezseniz varsayılan bir değere sahiptir. Ayrıca, seçenekle birlikte (-h / - help ile çalıştırıldığında kullanılacak) yardım argümanını bildirmeniz de kendi kendini belgelemektedir.

Genellikle argümanlarınızı aşağıdakilerle ayrıştırırsınız:

options, args = parser.parse_args()

Bu, varsayılan olarak, komut dosyasına geçirilen standart bağımsız değişkenleri ayrıştırır (sys.argv [1:])

options.query daha sonra komut dosyasına geçirdiğiniz değere ayarlanır.

Basitçe yaparak bir ayrıştırıcı oluşturursunuz

parser = optparse.OptionParser()

Bunların hepsi ihtiyacınız olan temel bilgilerdir. İşte bunu gösteren eksiksiz bir Python betiği:

import optparse

parser = optparse.OptionParser()

parser.add_option('-q', '--query',
    action="store", dest="query",
    help="query string", default="spam")

options, args = parser.parse_args()

print 'Query string:', options.query

Temel bilgileri gösteren 5 satır python.

Sample.py dosyasına kaydedin ve bir kez çalıştırın.

python sample.py

ve bir kere

python sample.py --query myquery

Bunun ötesinde, optparse'ın uzatılmasının çok kolay olduğunu göreceksiniz. Projelerimden birinde, alt komutları bir komut ağacına kolayca yerleştirmenizi sağlayan bir Komut sınıfı oluşturdum. Komutları birbirine zincirlemek için ağırlıklı olarak optparse kullanır. Birkaç satırda kolayca açıklayabileceğim bir şey değil, ancak ana sınıf depomun yanı sıra onu ve seçenek ayrıştırıcısını kullanan bir sınıfta dolaşmaktan çekinmeyin


9
Bu cevap çok açık ve takip edilmesi kolaydır - python 2.3 ila 2.6 için. Python 2.7+ için argparse artık standart kütüphanenin bir parçası olduğu ve optparse'ın kullanımdan kaldırıldığı için en iyi cevap değildir.
matt wilkie

Benim durumumda, yavaşlığı algılamak için uygulamamı profille paylaşmak istiyorum. [Tuna] ( github.com/nschloe/tuna ) adında başka bir araç var, bu da sadece uygulama ekleyerek tüm uygulamayı profil yapmamı sağlıyor -mcProfile -o program.profancak agrparcer bu argümanları yakalıyor, bu argümanları python exe'ye nasıl geçirebilirim ???
Yogeshwar

231

argparsegitmek için bir yoldur. İşte nasıl kullanılacağına dair kısa bir özet:

1) Başlat

import argparse

# Instantiate the parser
parser = argparse.ArgumentParser(description='Optional app description')

2) Bağımsız Değişken Ekle

# Required positional argument
parser.add_argument('pos_arg', type=int,
                    help='A required integer positional argument')

# Optional positional argument
parser.add_argument('opt_pos_arg', type=int, nargs='?',
                    help='An optional integer positional argument')

# Optional argument
parser.add_argument('--opt_arg', type=int,
                    help='An optional integer argument')

# Switch
parser.add_argument('--switch', action='store_true',
                    help='A boolean switch')

3) Ayrıştırma

args = parser.parse_args()

4) Erişim

print("Argument values:")
print(args.pos_arg)
print(args.opt_pos_arg)
print(args.opt_arg)
print(args.switch)

5) Değerleri Kontrol Edin

if args.pos_arg > 10:
    parser.error("pos_arg cannot be larger than 10")

kullanım

Doğru kullanım:

$ ./app 1 2 --opt_arg 3 --switch

Argument values:
1
2
3
True

Yanlış argümanlar:

$ ./app foo 2 --opt_arg 3 --switch
usage: convert [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
app: error: argument pos_arg: invalid int value: 'foo'

$ ./app 11 2 --opt_arg 3
Argument values:
11
2
3
False
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
convert: error: pos_arg cannot be larger than 10

Tam yardım:

$ ./app -h

usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]

Optional app description

positional arguments:
  pos_arg            A required integer positional argument
  opt_pos_arg        An optional integer positional argument

optional arguments:
  -h, --help         show this help message and exit
  --opt_arg OPT_ARG  An optional integer argument
  --switch           A boolean switch

10
Bu çok özlü ve kullanışlı ve resmi doküman (kolaylık olması için): docs.python.org/3/library/argparse.html
Christophe Roussy

1
Eğer argparse çok ayrıntılı bulursanız bunun yerine plac kullanın.
Nimitz14

76

Docopt kullanma

2012'den beri docopt adı verilen argüman ayrıştırma için çok kolay, güçlü ve gerçekten harika bir modül var . Dokümanlarından alınan bir örnek:

"""Naval Fate.

Usage:
  naval_fate.py ship new <name>...
  naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
  naval_fate.py ship shoot <x> <y>
  naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
  naval_fate.py (-h | --help)
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.

"""
from docopt import docopt


if __name__ == '__main__':
    arguments = docopt(__doc__, version='Naval Fate 2.0')
    print(arguments)

Budur Yani: 2 kod satırını artı doc dize olan esansiyel ve aldığınız senin argümanlar çözümlenir ve argümanlar nesne mevcut.

Python-fire kullanma

2017'den beri python-fire adlı başka bir serin modül var . Sıfır argüman ayrıştırma yaparken kodunuz için bir CLI arayüzü oluşturabilir . Belgelerden basit bir örnek (bu küçük program işlevi doublekomut satırına gösterir):

import fire

class Calculator(object):

  def double(self, number):
    return 2 * number

if __name__ == '__main__':
  fire.Fire(Calculator)

Komut satırından şunları çalıştırabilirsiniz:

> calculator.py double 10
20
> calculator.py double --number=15
30

4
docopt "kurulum gerektirmez" nasıl? bir python modülü olduğu için kurulması gerekiyor. 'ImportError: docopt adında bir modül yok'
hevesli

1
@keen python ile kesin olarak dahil değildir, ancak kurmanıza gerek yoktur: "docopt.py dosyasını projenize bırakabilirsiniz - kendi kendine yeten" - github.com/docopt/docopt
ndemou

9
sadece farklı yükleme tanımlarımız var - ve bunu gelecekteki okuyucular için belirtmek istedim.
düşkün

1
@keen Tanımınızı paylaşan insanlar için "kurulum yok" üzerine bir not ekledim :-)
ndemou

39

Yeni kalça yoludur argparseiçin bu nedenlerden. argparse> optparse> getopt

update: py2.7'den itibaren argparse standart kütüphanenin bir parçasıdır ve optparse kullanımdan kaldırılmıştır.


Ana bağlantınız 404'tür, bu yüzden aynı konuyu ele alan bir SO sorusunun bağlantısıyla değiştirdim.
Joe Holloway

28

Ben tercih tıklayın . Yönetim seçeneklerini özetler ve "(...) gerektiği kadar az kodla güzel bir komut satırı arabirimleri oluşturulabilir bir şekilde oluşturmaya izin verir".

İşte örnek kullanım:

import click

@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
              help='The person to greet.')
def hello(count, name):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo('Hello %s!' % name)

if __name__ == '__main__':
    hello()

Ayrıca otomatik olarak güzel biçimlendirilmiş yardım sayfaları oluşturur:

$ python hello.py --help
Usage: hello.py [OPTIONS]

  Simple program that greets NAME for a total of COUNT times.

Options:
  --count INTEGER  Number of greetings.
  --name TEXT      The person to greet.
  --help           Show this message and exit.

14

Hemen hemen herkes getopt kullanıyor

İşte doc için örnek kod:

import getopt, sys

def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
    except getopt.GetoptError:
        # print help information and exit:
        usage()
        sys.exit(2)
    output = None
    verbose = False
    for o, a in opts:
        if o == "-v":
            verbose = True
        if o in ("-h", "--help"):
            usage()
            sys.exit()
        if o in ("-o", "--output"):
            output = a

Kısacası, işte böyle.

İki tür seçeneğiniz var. Argüman alan ve anahtar gibi olanlar.

sys.argvHemen hemen edilir char** argvC. Like Programınıza ve ayrıştırmanın o sadece argümanlar adıdır ilk elemanını atlamak C:sys.argv[1:]

Getopt.getopt argümanda verdiğiniz kurala göre ayrıştırır.

"ho:v"Burada kısa argümanları anlatır: -ONELETTER. Bir argümanı kabul eden :araçlar -o.

Son ["help", "output="]olarak uzun argümanlar ( --MORETHANONELETTER) açıklanmaktadır . =Sonra çıktı bir kez daha bu çıkış bir argüman kabul anlamına gelir.

Sonuç, çiftin bir listesidir (seçenek, bağımsız değişken)

Bir seçenek ( --helpburada argolduğu gibi ) herhangi bir argümanı kabul etmezse , bölüm boş bir dizedir. Daha sonra genellikle bu listede döngü yapmak ve örnekte olduğu gibi seçenek adını test etmek istersiniz.

Umarım bu sana yardımcı olmuştur.


6
getoptPython'un daha yeni sürümlerinde kullanımdan kaldırıldığında bu cevap güncelliğini yitirdi.
shuttle87

1
@ shuttle87 python3.7.2'den itibaren getopthala kullanımdan kaldırılmamıştır… Ancak belgelerinde esas olarak C getopt()işlevini bilen kullanıcılar için sağlandığını ve diğer kullanıcılar argparseiçin daha az kod yazıp msgstr "daha iyi yardım ve hata mesajları" #:.
Skippy le Grand Gourou

14

optparseStandart kitaplık ile birlikte gelen kullanımı . Örneğin:

#!/usr/bin/env python
import optparse

def main():
  p = optparse.OptionParser()
  p.add_option('--person', '-p', default="world")
  options, arguments = p.parse_args()
  print 'Hello %s' % options.person

if __name__ == '__main__':
  main()

Kaynak: UNIX komut satırı araçları oluşturmak için Python kullanma

Ancak Python 2.7 optparse kullanımdan kaldırılmıştır, bakınız: Optparse yerine neden argparse kullanılır?


6

Her ihtimale karşı size gerekiyorsa, bu yardımcı olabilir gerekebilir kapmak Win32 üzerinde unicode argümanlar (2K, XP vs):


from ctypes import *

def wmain(argc, argv):
    print argc
    for i in argv:
        print i
    return 0

def startup():
    size = c_int()
    ptr = windll.shell32.CommandLineToArgvW(windll.kernel32.GetCommandLineW(), byref(size))
    ref = c_wchar_p * size.value
    raw = ref.from_address(ptr)
    args = [arg for arg in raw]
    windll.kernel32.LocalFree(ptr)
    exit(wmain(len(args), args))
startup()

Teşekkür ederim. Bu komut dosyası, başlangıç ​​komutlarını GVim'e iletirken yapmam gereken gerçekten karmaşık alıntılar yapmama yardımcı oldu.
telotortium

6

Hafif komut satırı bağımsız değişkeni varsayılanları

Her ne kadar argparseharika ve tam olarak belgelenmiş komut satırı anahtarları ve gelişmiş özellikler için doğru yanıt olsa da , basit konumsal bağımsız değişkenleri çok basit bir şekilde işlemek için işlev bağımsız değişkeni kullanabilirsiniz.

import sys

def get_args(name='default', first='a', second=2):
    return first, int(second)

first, second = get_args(*sys.argv)
print first, second

'Name' argümanı kod adını yakalar ve kullanılmaz. Test çıktısı şöyle görünür:

> ./test.py
a 2
> ./test.py A
A 2
> ./test.py A 20
A 20

Bazı varsayılan değerleri istediğim basit komut dosyaları için bunu oldukça yeterli buluyorum. Ayrıca, dönüş değerlerine bir tür baskı eklemek isteyebilirsiniz, aksi takdirde komut satırı değerlerinin tümü dize olur.


2
tırnak işaretleri def deyiminde uyuşmuyor.
historystamp

3

Ben getopt tercih optparse. Bu çok bildirim niteliğindedir: Ona seçeneklerin adlarını ve sahip olmaları gereken etkileri söylersiniz (örneğin, bir boolean alanı ayarlamak) ve size belirttiğiniz özelliklere göre doldurulmuş bir sözlüğü geri verir.

http://docs.python.org/lib/module-optparse.html


3

Bence daha büyük projeler için en iyi yol tercih etmek, ancak kolay bir yol arıyorsanız, belki http://werkzeug.pocoo.org/documentation/script sizin için bir şeydir.

from werkzeug import script

# actions go here
def action_foo(name=""):
    """action foo does foo"""
    pass

def action_bar(id=0, title="default title"):
    """action bar does bar"""
    pass

if __name__ == '__main__':
    script.run()

Temelde her action_ * işlevi komut satırına maruz kalır ve ücretsiz olarak güzel bir yardım mesajı oluşturulur.

python foo.py 
usage: foo.py <action> [<options>]
       foo.py --help

actions:
  bar:
    action bar does bar

    --id                          integer   0
    --title                       string    default title

  foo:
    action foo does foo

    --name                        string

Otomatik argüman oluşturma: kullanarak küçük bir paket geliştirdim declarative_parser. Tabii ki, biri werkzeug ile çalışıyorsa, tutmak daha iyi olabilir werkzung.script. Her neyse, bu yaklaşımın büyük bir hayranıyım.
krassowski

3

Argparse kodu gerçek uygulama kodundan daha uzun olabilir!

En popüler argüman ayrıştırma seçeneklerinde bulduğum bir sorun, parametreleriniz mütevazı ise, bunları belgeleyen kodun sağladığı faydaya göre orantısız olarak büyük olmasıdır.

Tartışmayı çözümleme sahnesine göreceli yeni gelen (sanırım) plas .

Argparse ile bazı onaylanmış ödünleşmeler yapar, ancak satır içi belgeleri kullanır ve yalnızca main()tür işlev işlevi etrafına sarar :

def main(excel_file_path: "Path to input training file.",
     excel_sheet_name:"Name of the excel sheet containing training data including columns 'Label' and 'Description'.",
     existing_model_path: "Path to an existing model to refine."=None,
     batch_size_start: "The smallest size of any minibatch."=10.,
     batch_size_stop:  "The largest size of any minibatch."=250.,
     batch_size_step:  "The step for increase in minibatch size."=1.002,
     batch_test_steps: "Flag.  If True, show minibatch steps."=False):
"Train a Spacy (http://spacy.io/) text classification model with gold document and label data until the model nears convergence (LOSS < 0.5)."

    pass # Implementation code goes here!

if __name__ == '__main__':
    import plac; plac.call(main)

Bilgi noktası: en düzgün plac kullanımı (örnekte gösterildiği gibi) yalnızca Python 3.x içindir, çünkü 3.x fonksiyon ek açıklamaları kullanır.
barny

1

consoleargs burada belirtilmeyi hak ediyor. Kullanımı çok kolaydır. Bunu kontrol et:

from consoleargs import command

@command
def main(url, name=None):
  """
  :param url: Remote URL 
  :param name: File name
  """
  print """Downloading url '%r' into file '%r'""" % (url, name)

if __name__ == '__main__':
  main()

Şimdi konsolda:

% python demo.py --help
Usage: demo.py URL [OPTIONS]

URL:    Remote URL 

Options:
    --name -n   File name

% python demo.py http://www.google.com/
Downloading url ''http://www.google.com/'' into file 'None'

% python demo.py http://www.google.com/ --name=index.html
Downloading url ''http://www.google.com/'' into file ''index.html''

Deklaratif -ayrıştırıcıda benzer bir yaklaşım kullandım , dokümanlardaki argüman kesinti (yazım, docstrings, kwargs) konusuna bakın . Başlıca farklılıklar: python3, tip ipuçları, pip-takılabilir.
krassowski

1
2012'de son taahhüt
Boris

0

İşte benim için işe yarayan bir kütüphane değil, bir yöntem.

Buradaki hedefler ters, her bir argüman tek bir satırla ayrıştırılır, argümanlar okunabilirlik için sıralanır, kod basittir ve herhangi bir özel modüle (sadece os + sys) bağlı değildir, eksik veya bilinmeyen argümanları incelikle uyarır , / range () döngüsü için basit kullanın ve python 2.x ve 3.x üzerinde çalışır

Gösterilen iki geçiş bayrağı (-d, -v) ve bağımsız değişkenler (-i xxx ve -o xxx) tarafından kontrol edilen iki değerdir.

import os,sys

def HelpAndExit():
    print("<<your help output goes here>>")
    sys.exit(1)

def Fatal(msg):
    sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
    sys.exit(1)

def NextArg(i):
    '''Return the next command line argument (if there is one)'''
    if ((i+1) >= len(sys.argv)):
        Fatal("'%s' expected an argument" % sys.argv[i])
    return(1, sys.argv[i+1])

### MAIN
if __name__=='__main__':

    verbose = 0
    debug   = 0
    infile  = "infile"
    outfile = "outfile"

    # Parse command line
    skip = 0
    for i in range(1, len(sys.argv)):
        if not skip:
            if   sys.argv[i][:2] == "-d": debug ^= 1
            elif sys.argv[i][:2] == "-v": verbose ^= 1
            elif sys.argv[i][:2] == "-i": (skip,infile)  = NextArg(i)
            elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
            elif sys.argv[i][:2] == "-h": HelpAndExit()
            elif sys.argv[i][:1] == "-":  Fatal("'%s' unknown argument" % sys.argv[i])
            else:                         Fatal("'%s' unexpected" % sys.argv[i])
        else: skip = 0

    print("%d,%d,%s,%s" % (debug,verbose,infile,outfile))

NextArg () öğesinin amacı, eksik verileri kontrol ederken bir sonraki bağımsız değişkeni döndürmektir ve NextArg () kullanıldığında 'atla' döngüsü atlayarak bir satırı aşağıya ayrıştırır.


0

Erco'nun gerekli konumsal argümanlara ve isteğe bağlı argümanlara izin verme yaklaşımını genişlettim. Bunlar -d, -v vb argümanlarından önce gelmelidir.

Konumsal ve isteğe bağlı bağımsız değişkenler, sırasıyla PosArg (i) ve OptArg (i, varsayılan) ile alınabilir. İsteğe bağlı bir argüman bulunduğunda, seçeneklerin (ör. -İ) aranmasının başlangıç ​​konumu, 'beklenmedik' bir ölümcül oluşmasını önlemek için 1 ileri hareket ettirilir.

import os,sys


def HelpAndExit():
    print("<<your help output goes here>>")
    sys.exit(1)

def Fatal(msg):
    sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
    sys.exit(1)

def NextArg(i):
    '''Return the next command line argument (if there is one)'''
    if ((i+1) >= len(sys.argv)):
        Fatal("'%s' expected an argument" % sys.argv[i])
    return(1, sys.argv[i+1])

def PosArg(i):
    '''Return positional argument'''
    if i >= len(sys.argv):
        Fatal("'%s' expected an argument" % sys.argv[i])
    return sys.argv[i]

def OptArg(i, default):
    '''Return optional argument (if there is one)'''
    if i >= len(sys.argv):
        Fatal("'%s' expected an argument" % sys.argv[i])
    if sys.argv[i][:1] != '-':
        return True, sys.argv[i]
    else:
        return False, default


### MAIN
if __name__=='__main__':

    verbose = 0
    debug   = 0
    infile  = "infile"
    outfile = "outfile"
    options_start = 3

    # --- Parse two positional parameters ---
    n1 = int(PosArg(1))
    n2 = int(PosArg(2))

    # --- Parse an optional parameters ---
    present, a3 = OptArg(3,50)
    n3 = int(a3)
    options_start += int(present)

    # --- Parse rest of command line ---
    skip = 0
    for i in range(options_start, len(sys.argv)):
        if not skip:
            if   sys.argv[i][:2] == "-d": debug ^= 1
            elif sys.argv[i][:2] == "-v": verbose ^= 1
            elif sys.argv[i][:2] == "-i": (skip,infile)  = NextArg(i)
            elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
            elif sys.argv[i][:2] == "-h": HelpAndExit()
            elif sys.argv[i][:1] == "-":  Fatal("'%s' unknown argument" % sys.argv[i])
            else:                         Fatal("'%s' unexpected" % sys.argv[i])
        else: skip = 0

    print("Number 1 = %d" % n1)
    print("Number 2 = %d" % n2)
    print("Number 3 = %d" % n3)
    print("Debug    = %d" % debug)
    print("verbose  = %d" % verbose)
    print("infile   = %s" % infile)
    print("outfile  = %s" % outfile) 
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.