Qual é a melhor maneira de analisar argumentos de linha de comando?

votos
145

Qual é a mais fácil , tersest , e mais flexível método ou biblioteca para analisar argumentos de linha de comando Python?

Publicado 21/08/2008 em 15:24
fonte usuário
Em outras línguas...                            


15 respostas

votos
126

Essa resposta sugere optparseque é apropriado para versões mais antigas do Python. Para Python e 2.7 acima, argparsesubstitui optparse. Veja esta resposta para mais informações.

Como outras pessoas apontou, você é melhor fora de ir com optparse sobre getopt. getopt é praticamente um mapeamento um-para-um do getopt padrão (3) funções de biblioteca C, e não é muito fácil de usar.

optparse, sendo um pouco mais detalhado, é muito melhor estruturada e mais simples para estender mais tarde.

Aqui está uma linha típica para adicionar uma opção para o seu analisador:

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

É praticamente fala por si; em tempo de processamento, ele irá aceitar -q ou --query como opções, armazenar o argumento em um atributo chamado consulta e tem um valor padrão se você não especificar isso. É também auto-documentando em que você declare o argumento de ajuda (que será usado quando executado com -h / - help) ali mesmo com a opção.

Normalmente você analisar seus argumentos com:

options, args = parser.parse_args()

Isto irá, por padrão, analisar os argumentos padrão passados ​​para o script (sys.argv [1:])

options.query será então definido para o valor passado para o script.

Você cria um analisador simplesmente fazendo

parser = optparse.OptionParser()

Estes são todos os fundamentos que você precisa. Aqui está um script Python completo que mostra isso:

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 linhas de python que mostram o básico.

Salve-o em sample.py, e executá-lo uma vez com

python sample.py

e uma vez com

python sample.py --query myquery

Além disso, você vai achar que optparse é muito fácil de estender. Em um dos meus projetos, eu criei uma classe de comando que permite que você subcommands ninho em uma árvore de comando facilmente. Ele usa optparse fortemente aos comandos cadeia juntos. Não é algo que eu possa facilmente explicar em poucas linhas, mas fique à vontade para navegar ao redor no meu repositório para a classe principal, assim como uma classe que usa e o analisador opção

Respondeu 25/08/2008 em 22:11
fonte usuário

votos
101

Outras respostas fazer mencionar que argparseé o caminho a percorrer para nova Python, mas não dão exemplos de uso. Para completar, aqui é um breve resumo de como usar argparse:

1) inicializar

import argparse

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

2) Adicionar Argumentos

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

args = parser.parse_args()

4) Acesso

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

5) Verifique Valores

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

Uso

uso correto:

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

Argument values:
1
2
3
True

Argumentos incorretos:

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

ajuda completa:

$ ./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
Respondeu 27/05/2015 em 21:21
fonte usuário

votos
51

usando docopt

Desde 2012 Python tem um muito fácil, poderoso e realmente legal módulo para análise argumento chamado docopt . Ele funciona com o Python 2.6 a 3.5 e não necessita de instalação (apenas copiá-lo). Aqui está um exemplo tirado da sua documentação:

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

Então é isso: 2 linhas de código mais o seu doc string que é essencial e você começa seus argumentos analisados e disponíveis em seus argumentos objeto. Eu disse que isso é legal, não disse ;-)

Usando python-fogo

Desde 2017 python-fogo tem outro módulo legal que pode dar uma interface CLI ao seu código com você fazendo de zero argumento de análise. Aqui está um exemplo simples da documentação (este pequeno programa expõe função doublena linha de comando):

import fire

class Calculator(object):

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

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

Na linha de comando, você pode executar:

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

Impressionante, não é?

Respondeu 04/05/2013 em 18:51
fonte usuário

votos
35

A nova forma de quadril é argparsepara essas razões. argparse> optparse> getopt

UPDATE: A partir de py2.7 argparse é parte da biblioteca padrão e optparse está obsoleta.

Respondeu 11/06/2009 em 08:54
fonte usuário

votos
15

Praticamente todo mundo está usando getopt

Aqui está o código exemplo para o 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

Assim, em uma palavra, aqui é assim que funciona.

Você tem dois tipos de opções. Aqueles que estão recebendo argumentos, e aqueles que são como interruptores.

sys.argvé praticamente o seu char** argvem C. Como em C você pular o primeiro elemento que é o nome do seu programa e analisar apenas os argumentos:sys.argv[1:]

Getopt.getopt vai analisá-lo de acordo com a regra que você dá no argumento.

"ho:v"aqui descreve as curtas argumentos: -ONELETTER. O :meio que -oaceita um argumento.

Finalmente ["help", "output="]descreve longos argumentos ( --MORETHANONELETTER). A =saída após mais uma vez significa que a saída aceita um argumento.

O resultado é uma lista de pares (opção, argumento)

Se uma opção não aceita nenhum argumento (como --helpaqui) a argparte é uma string vazia. Você, então, geralmente querem circuito nesta lista e testar o nome da opção como no exemplo.

Espero que isso te ajudou.

Respondeu 21/08/2008 em 15:26
fonte usuário

votos
14

Use optparseo que vem com a biblioteca padrão. Por exemplo:

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

Fonte: Usando Python para criar ferramentas de linha de comando UNIX

No entanto a partir de Python 2.7 optparse está obsoleta, consulte: Por que usar argparse em vez de optparse?

Respondeu 21/08/2008 em 15:25
fonte usuário

votos
9

Eu prefiro Clique . Ele abstrai opções de gerenciamento e permite que "(...) criando belas interfaces de linha de comando em uma forma combináveis com o mínimo de código, conforme necessário".

Aqui é exemplo de uso:

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

Ele também gera automaticamente bem formatado páginas de ajuda:

$ 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.
Respondeu 21/11/2014 em 20:00
fonte usuário

votos
6

Apenas no caso você pode precisar, isso pode ajudar se você precisa pegar argumentos do Unicode no 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()
Respondeu 21/08/2008 em 15:59
fonte usuário

votos
4

Eu acho que a melhor maneira para projetos maiores é optparse, mas se você está procurando uma maneira fácil, talvez http://werkzeug.pocoo.org/documentation/script é algo para você.

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

Então, basicamente, todas as funções Ação_ * está exposta a linha de comando e uma boa ajuda mensagem é gerada de forma gratuita.

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
Respondeu 27/08/2008 em 20:27
fonte usuário

votos
3

Eu prefiro optparse para Getopt. É muito declarativa: você diga a ele os nomes das opções e os efeitos que devem ter (por exemplo, definir um campo boolean), e entrega-lhe de volta um dicionário ocupada de acordo com suas especificações.

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

Respondeu 21/08/2008 em 16:22
fonte usuário

votos
2

defaults argumento de linha de comando leve

Embora argparseé grande e é a resposta certa para opções de linha de comando totalmente documentados e recursos avançados, você pode usar a função padrões argumento para alças simples argumentos posicionais muito simples.

import sys

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

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

O argumento 'nome' captura o nome do script e não é usado. saída de teste parecido com este:

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

Para scripts simples onde eu só querem alguns valores padrão, acho que este suficiente. Você também pode querer incluir algum tipo de coerção nos valores de retorno ou valores de linha de comando serão todos cordas.

Respondeu 05/04/2017 em 14:26
fonte usuário

votos
2

consoleargs merece ser mencionado aqui. É muito fácil de usar. Confira:

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

Agora no console:

% 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''
Respondeu 30/06/2012 em 06:43
fonte usuário

votos
0

Eu estendi a abordagem de Erco para permitir argumentos posicionais necessários e para argumentos opcionais. Estes devem preceder o -d, -v etc. argumentos.

argumentos posicionais e opcionais podem ser recuperados com PosArg (i) e OPTARG (i, padrão), respectivamente. Quando um argumento opcional é encontrada a posição inicial da busca de opções (por exemplo, -i) é movido 1 frente, para evitar um 'inesperada' fatal.

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) 
Respondeu 24/07/2018 em 12:32
fonte usuário

votos
0

Argparse código pode ser maior do que o código de implementação real!

Isso é um problema que eu encontrar com a maioria das opções argumento de análise populares é que, se os parâmetros são apenas modestos, o código para documentá-los torna-se desproporcionalmente grande para o benefício que eles fornecem.

Um recém-chegado em relação à cena o argumento de análise (eu acho) é plac .

Faz alguns trade-offs reconhecido com argparse, mas usa a documentação em linha e envolve simplesmente em torno main()Função Tipo:

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)
Respondeu 05/07/2018 em 07:17
fonte usuário

votos
0

Aqui está um método, não uma biblioteca, que parece funcionar para mim.

Os objetivos aqui são para ser conciso, cada argumento analisado por uma única linha, os argumentos alinhados para facilitar a leitura, o código é simples e não depende de quaisquer módulos especiais (somente OS + sys), adverte sobre a falta ou argumentos desconhecidos graciosamente , usar um simples para / gama () ciclo, e funciona em 2.x pitão e 3.x

Mostram-se duas bandeiras de alternância (-d, -v), e dois valores controlados por argumentos (-i xxx xxx e -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))

O objetivo do NextArg () é retornar o próximo argumento durante a verificação de dados em falta, e 'pular' ignora o loop quando NextArg () é usado, mantendo a bandeira analisar até forros.

Respondeu 09/04/2016 em 12:45
fonte usuário

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