Hva er den beste måten å analysere kommandolinjeargumenter?

stemmer
168

Hva er den enkleste , tersest , og mest fleksible metoden eller bibliotek for parsing Python kommandolinjeargumenter?

Publisert på 21/08/2008 klokken 14:24
kilden bruker
På andre språk...                            


15 svar

stemmer
139

Dette svaret tyder på optparsenoe som er passende for eldre Python versjoner. For Python 2.7 og høyere, argparseerstatter optparse. Se dette svaret for mer informasjon.

Som andre påpekt, er du bedre å gå med optparse løpet getopt. getopt er ganske mye en en-til-en kartlegging av standard getopt (3) C bibliotekfunksjoner, og ikke veldig lett å bruke.

optparse, samtidig som en litt mer detaljert, er mye bedre strukturert og enklere å utvide senere.

Her er en typisk linje for å legge til et alternativ til parser:

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

Det taler ganske mye for seg selv; på behandlingstiden, vil den godta -q eller --query som alternativer, lagre argument i et attributt kalt spørringen og har en standardverdi hvis du ikke spesifiserer det. Det er også selv dokumentere at du deklarerer hjelp argument (som skal brukes når det kjøres med -h / - hjelp) der med alternativet.

Vanligvis du analysere dine argumenter med:

options, args = parser.parse_args()

Dette vil, som standard, analysere standard argumenter som sendes til skriptet (sys.argv [1:])

options.query vil da bli satt til verdien du gått over til manuset.

Du oppretter en parser bare ved å gjøre

parser = optparse.OptionParser()

Dette er alle grunnleggende du trenger. Her er en komplett Python-skript som viser dette:

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

5 linjer med python som viser deg det grunnleggende.

Lagre det i sample.py, og kjøre den en gang med

python sample.py

og en gang med

python sample.py --query myquery

Utover det, vil du finne at optparse er svært enkelt å utvide. I en av mine prosjekter, jeg laget en Command klasse som lar deg reir kommandoene i en kommando tre enkelt. Den bruker optparse tungt til kjede kommandoer sammen. Det er ikke noe jeg kan lett forklare på noen få linjer, men gjerne surfe rundt i min oppbevaringssted for hovedklassen, samt en klasse som bruker det og muligheten parser

Svarte 25/08/2008 kl. 21:11
kilden bruker

stemmer
119

Andre svar gjøre nevne at argparseer veien å gå for ny Python, men ikke gi bruk eksempler. For fullstendighet, her er en kort oppsummering av hvordan du bruker argparse:

1) Initial

import argparse

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

2) Legg Argumenter

# 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) Analyse

args = parser.parse_args()

4) Tilgang

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

5) Sjekk Verdier

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

bruk

Riktig bruk:

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

Argument values:
1
2
3
True

Uriktige argumenter:

$ ./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

Full hjelp:

$ ./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
Svarte 27/05/2015 kl. 21:21
kilden bruker

stemmer
54

Bruke docopt

Siden 2012 Python har en veldig enkel, kraftig og veldig kult modul for argument parsing kalt docopt . Det fungerer med Python 2.6 til 3.5, og trenger ingen installasjon (bare kopiere det). Her er et eksempel hentet fra den dokumentasjon:

"""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)

Så dette er det: 2 linjer med kode pluss doc streng som er viktig, og du får dine argumenter analyseres og tilgjengelig i dine argumenter objekt. Jeg sa at det er kult, ikke sant ;-)

Bruke python-brann

Siden 2017 python-brannen har en annen kul modul som kan gi en CLI-grensesnittet til koden med det du gjør null argument parsing. Her er et enkelt eksempel fra dokumentasjonen (dette lille programmet eksponerer funksjon doublei kommandolinjen):

import fire

class Calculator(object):

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

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

Fra kommandolinjen, kan du kjøre:

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

Awesome er det ikke?

Svarte 04/05/2013 kl. 17:51
kilden bruker

stemmer
35

Den nye hip måten er argparsefor disse grunner. argparse> optparse> getopt

Oppdatering: Per py2.7 argparse er en del av standard bibliotek og optparse er foreldet.

Svarte 11/06/2009 kl. 07:54
kilden bruker

stemmer
15

Ganske mye alle bruker getopt

Her er eksempel koden for doc:

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

Så i et ord, her er hvordan det fungerer.

Du har to typer opsjoner. De som mottar argumenter, og de som er akkurat som brytere.

sys.argver ganske mye char** argvi C. Som i C du hopper over det første elementet som er navnet på programmet og analysere bare argumentene:sys.argv[1:]

Getopt.getopt vil analysere det i henhold til regelen du gir i argumentet.

"ho:v"her beskriver de korte argumenter: -ONELETTER. Det :betyr at -ogodtar en argument.

Til slutt ["help", "output="]beskriver lange argumenter ( --MORETHANONELETTER). Den =etter utgang igjen vil si at produksjonen tar ett argumenter.

Resultatet er en liste over par (alternativ, argument)

Hvis et alternativ ikke aksepterer noe argument (som --helpher) den argdelen er en tom streng. Du kan deretter vanligvis ønsker å sløyfe på denne listen og teste navnet alternativet som i eksempelet.

Jeg håper dette hjalp deg.

Svarte 21/08/2008 kl. 14:26
kilden bruker

stemmer
14

Bruk optparsesom kommer med standard bibliotek. For eksempel:

#!/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()

Kilde: Bruke Python for å lage UNIX kommandolinje verktøy

Men som av Python 2.7 optparse er foreldet, se: Hvorfor bruke argparse snarere enn optparse?

Svarte 21/08/2008 kl. 14:25
kilden bruker

stemmer
10

Jeg foretrekker Klikk . Det abstracts administrere alternativer og lar "(...) å skape vakre kommandolinjegrensesnitt i en composable måte med så lite kode som er nødvendig".

Her er eksempel bruk:

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()

Det også automatisk genererer pent formatert hjelpesider:

$ 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.
Svarte 21/11/2014 kl. 20:00
kilden bruker

stemmer
6

Bare i tilfelle må du kanskje, kan dette hjelpe hvis du trenger å ta Unicode argumenter på Win32 (2K, XP etc):


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()
Svarte 21/08/2008 kl. 14:59
kilden bruker

stemmer
4

Jeg tror den beste måten for større prosjekter er optparse, men hvis du er ute etter en enkel måte, kanskje http://werkzeug.pocoo.org/documentation/script er noe for deg.

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()

Så i utgangspunktet hver funksjon action_ * utsettes for kommandolinjen og et vakkert hjelpemelding genereres gratis.

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
Svarte 27/08/2008 kl. 19:27
kilden bruker

stemmer
3

Jeg foretrekker optparse til getopt. Det er veldig deklarative: du forteller det navnene på alternativene og den effekten de skal ha (for eksempel sette en boolsk felt), og det hender du tilbake en ordbok befolket henhold til dine spesifikasjoner.

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

Svarte 21/08/2008 kl. 15:22
kilden bruker

stemmer
2

Lett kommandolinje argument mislighold

Selv argparseer flott og er det rette svaret for fullt dokumentert kommandolinjebrytere og avanserte funksjoner, kan du bruke funksjonsargument som standard håndtak enkle posisjon argumenter veldig enkelt.

import sys

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

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

The 'name' argument fanger skriptet navn og blir ikke brukt. Test resultatet ser slik ut:

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

For enkle skript der jeg bare ønsker noen standardverdier, finner jeg dette helt tilstrekkelig. Du kan også være lurt å ta med noen type tvang i returverdier eller kommandolinje verdier vil alle være strenger.

Svarte 05/04/2017 kl. 14:26
kilden bruker

stemmer
2

consoleargs fortjener å bli nevnt her. Det er veldig enkelt å bruke. Sjekk det ut:

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()

Nå i konsollen:

% 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''
Svarte 30/06/2012 kl. 05:43
kilden bruker

stemmer
0

Jeg utvidet Erco tilnærming for å tillate nødvendige posisjon argumenter og for valgfrie argumenter. Disse bør forut for d, v etc. argumenter.

Posisjonelle og valgfrie argumenter kan hentes med PosArg (i) og OptArg (i, standard) hhv. Når en valgfri argument er funnet startposisjonen for å lete etter valg (f.eks -i) beveges en fremover for å unngå å forårsake en 'uventet' dødelig.

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) 
Svarte 24/07/2018 kl. 12:32
kilden bruker

stemmer
0

Argparse koden kan være lengre enn selve gjennomføringen koden!

Det er et problem jeg finner med de fleste populære argument parsing alternativene er at hvis parametere er bare beskjedne, blir koden for å dokumentere dem uforholdsmessig stor til fordel de gir.

En relativ ny comer til argumentet parsing scene (tror jeg) er plac .

Det gjør at noen anerkjente avveininger med argparse, men bruker inline dokumentasjon og brytes bare rundt main()typen funksjon funksjon:

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)
Svarte 05/07/2018 kl. 07:17
kilden bruker

stemmer
0

Her er en metode, ikke et bibliotek, som synes å fungere for meg.

Målene her er å være avvisende, hvert argument analyseres av en enkelt linje, de args stille opp for lesbarhet, er koden enkel og er ikke avhengig av noen spesielle moduler (kun os + sys), advarer om manglende eller ukjente argumenter grasiøst ved å bruke en enkel for / område () sløyfe, og arbeider på tvers av python 2.x og 3.x

Vist er to vippe- flagg (-d, -v), og to verdier kontrollert av argumenter (-i xxx xxx og o).

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))

Målet med NextArg () er for å returnere den neste argumentet mens sjekke for manglende data, og 'hoppe over' hopper sløyfen når NextArg () blir benyttet, og holder flagget parsing ned til en liners.

Svarte 09/04/2016 kl. 12:45
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more