コマンドライン引数を解析する最良の方法は何ですか?[閉まっている]


251

Pythonコマンドライン引数を解析するための最も簡単で、最も簡潔で、最も柔軟なメソッドまたはライブラリは何ですか?

回答:


183

この回答は、optparseどちらが古いバージョンのPythonに適しているかを示唆しています。Python 2.7以降でargparseは、を置き換えoptparseます。詳細については、この回答を参照してください。

他の人が指摘したように、あなたはgetoptよりもoptparseを使うほうが良いです。getoptは、標準のgetopt(3)Cライブラリ関数のほぼ1対1のマッピングであり、非常に使いやすいものではありません。

optparseは少し冗長ですが、構造がずっと良く、後で拡張するのも簡単です。

パーサーにオプションを追加する一般的な行は次のとおりです。

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

それはほとんどそれ自体のために語っています。処理時に、-qまたは--queryをオプションとして受け入れ、引数をqueryという属性に格納し、指定しない場合はデフォルト値を使用します。また、オプションでヘルプ引数(-h /-helpを使用して実行するときに使用されます)を宣言するという点でも自己文書化されています。

通常、次のコマンドを使用して引数を解析します。

options, args = parser.parse_args()

これにより、デフォルトで、スクリプトに渡された標準引数が解析されます(sys.argv [1:])

options.queryは、スクリプトに渡した値に設定されます。

あなたは単に行うことでパーサーを作成します

parser = optparse.OptionParser()

これらはあなたが必要とするすべての基本です。これを示す完全なPythonスクリプトは次のとおりです。

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行のpython。

それをsample.pyに保存して、一度実行してください

python sample.py

そして一度

python sample.py --query myquery

さらに、optparseの拡張は非常に簡単です。私のプロジェクトの1つで、コマンドツリーにサブコマンドを簡単にネストできるようにするCommandクラスを作成しました。optparseを多用してコマンドをチェーン化します。これは数行で簡単に説明できるものではありませんが、メインクラスとそれを使用するクラスとオプションパーサーのリポジトリを自由に参照してください。


9
この答えは素晴らしく明確でわかりやすい-Python 2.3から2.6まで。Python 2.7以降では、argparseが標準ライブラリの一部になり、optparseが廃止されたため、これは最良の答えではありません。
マットウィルキー

私の場合、アプリケーションのプロファイルを作成して速度の低下を検出したいと思います。[tuna](github.com/nschloe/tuna)と呼ばれる別のツールがあります。これにより-mcProfile -o program.prof、agrsを追加するだけでアプリケーション全体のプロファイルを作成できますが、agrparcerがこれらの引数をキャプチャしています。これらの引数をpython exeに渡す方法は?
Yogeshwar

231

argparse行く方法です。これを使用する方法の短い要約はここにあります:

1)初期化

import argparse

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

2)引数を追加する

# 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)解析

args = parser.parse_args()

4)アクセス

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

5)値を確認する

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

使用法

正しい使い方:

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

Argument values:
1
2
3
True

不正な引数:

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

完全なヘルプ:

$ ./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
これは非常に簡潔で便利です。公式ドキュメント(便宜上)は次のとおり
Christophe Roussy

1
argparseが冗長すぎる場合は、代わりにplacを使用してください
Nimitz14

76

docoptの使用

2012年以降、docoptと呼ばれる引数解析用の非常に簡単で強力な、本当にクールなモジュールがあります。ドキュメントからの例を次に示します。

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

つまり、これは次のとおりです。2行のコードとドキュメント文字列不可欠であり、引数を解析して引数オブジェクトで使用できます。

python-fireの使用

2017年以降、python-fireと呼ばれる別のクールなモジュールがあります。それはあなたがやってとあなたのコードのためのCLIインターフェースを生成することができ、ゼロ引数解析を。ドキュメントの簡単な例を次に示します(この小さなプログラムは、関数doubleをコマンドラインに公開します)。

import fire

class Calculator(object):

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

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

コマンドラインから、次のコマンドを実行できます。

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

4
docoptはどのようにして「インストール不要」ですか?これはpythonモジュールなので、インストールする必要があります。'ImportError:docoptという名前のモジュールはありません'
鋭敏な

1
それは確かにのpythonに含まれていないが、あなたはそれをインストールする必要はありません@keen:「あなたは自分のプロジェクトにdocopt.pyファイルをドロップすることができます-それは自己完結型である」 - github.com/docopt/docopt
ndemou

9
インストールの定義が異なるだけです。将来の読者のためにそれを指摘したいと思います。
熱心

1
@keen定義を共有している人のために、「インストールしない」というメモを追加しました:-)
ndemou

39

新しいヒップ方法があるargparseため、これらの理由。argparse> optparse> getopt

更新: py2.7以降、argparseは標準ライブラリの一部であり、optparseは非推奨です。


メインリンクは404なので、同じトピックを扱うSOの質問へのリンクに置き換えました。
Joe Holloway、

28

私はクリックを好む。それはオプションの管理を抽象化し、「(...)必要な最小限のコードで構成可能な方法で美しいコマンドラインインターフェイスを作成する」ことを可能にします。

次に使用例を示します。

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

また、適切にフォーマットされたヘルプページを自動的に生成します。

$ 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

ほとんどすべての人がgetoptを使用しています

これがドキュメントのサンプルコードです:

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

つまり、一言で言えば、それがどのように機能するかです。

2種類のオプションがあります。議論を受けている人や、まるでスイッチのような人。

sys.argvchar** argvCとほぼ同じです。Cと同様に、プログラムの名前である最初の要素をスキップし、引数のみを解析します。sys.argv[1:]

Getopt.getopt 引数で指定したルールに従って解析します。

"ho:v"ここでは、短い引数について説明します-ONELETTER:手段-o1つの引数を受け入れます。

最後に["help", "output="]、長い引数について説明します(--MORETHANONELETTER)。=後の出力は再びその出力は1つの引数を受け付けます。

結果はカップル(オプション、引数)のリストです

オプションが引数を受け入れない場合(--helpここなど)argパーツは空の文字列です。次に、通常はこのリストをループして、例のようにオプション名をテストします。

これがお役に立てば幸いです。


6
getopt新しいバージョンのPythonでは非推奨となったため、この回答は古くなっています。
シャトル87 2014

1
@ shuttle87現在、python3.7.2 getoptは非推奨ではありません…しかし、そのドキュメントには、主にC getopt()関数に精通しているユーザー向けに提供されており、他のユーザーにargparseは「より少ないコードを記述してヘルプとエラーメッセージの改善」をご覧ください。
Skippy le Grand Gourou

14

optparse標準ライブラリに付属している使用。例えば:

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

ソース:Pythonを使用してUNIXコマンドラインツールを作成する

ただし、Python 2.7のoptparseは非推奨です。「optparseではなくargparseを使用する理由」を参照してください


6

必要に応じて、Win32(2K、XPなど)でUnicode引数を取得する必要がある場合に役立ちます。


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

ありがとうございました。このスクリプトは、スタートアップコマンドをGVimに渡すときに実行する必要のある、非常に複雑な引用を行うのに役立ちました。
テロトリウム2013

6

軽量のコマンドライン引数のデフォルト

argparse素晴らしいですし、完全に文書化コマンドラインスイッチと高度な機能のための正しい答えである、あなたは非常に簡単にハンドルに簡単位置引数に関数の引数のデフォルト値を使用することができます。

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'引数はスクリプト名をキャプチャし、使用されません。テスト出力は次のようになります。

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

いくつかのデフォルト値が必要なだけの単純なスクリプトの場合、これで十分です。戻り値に型強制を含めることもできます。そうしないと、コマンドライン値はすべて文字列になります。


2
引用符がdefステートメントで一致していません。
historystamp 2018


3

大規模なプロジェクトに最適な方法はoptparseだと思いますが、簡単な方法を探している場合は、http://werkzeug.pocoo.org/documentation/scriptが適しています。

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

したがって、基本的にすべての関数action_ *はコマンドラインに公開され、便利なヘルプメッセージが無料で生成されます。

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

引数の自動作成を利用した小さなパッケージを開発しましたdeclarative_parser。もちろん、werkzeugを使用している場合は、を保持することをお勧めしwerkzung.scriptます。とにかく、私はそのようなアプローチの大ファンです。
Krassowski、2017年

3

Argparseコードは実際の実装コードより長くなる可能性があります!

これは、最も一般的な引数解析オプションで私が見つけた問題です。パラメーターが控えめなだけの場合、それらを文書化するコードは、提供する利点に対して不釣り合いに大きくなります。

議論の構文解析シーン(私は思う)の比較的新しい人はplacです。

argparseとのトレードオフは認められていますが、インラインドキュメントを使用し、単純にmain()関数型関数をラップしています。

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)

情報のポイント:(例に示されている)placの最も近い使用は、3.x関数アノテーションを使用するため、Python 3.xのみです。
バーニー

1

consoleargsはここで言及するに値します。とても使いやすいです。見てみな:

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

今コンソールで:

% 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''

私はdeclarative-parserで同様のアプローチを使用しました。ドキュメントで引数の推論(タイピング、ドキュメント文字列、kwargs)を参照してください。主な違い:python3、タイプのヒント、pip-installable。
Krassowski

1
2012年最後のコミット
ボリス

0

これはライブラリではなくメソッドで、私にとってはうまくいくようです。

ここでの目標は簡潔にすることです。各引数は1行で解析され、argsは読みやすくするために整列します。コードは単純で、特別なモジュール(os + sysのみ)に依存せず、欠落または不明な引数について適切に警告します、単純なfor / range()ループを使用して、Python 2.xおよび3.xで機能します

2つのトグルフラグ(-d、-v)、および引数(-i xxxおよび-o xxx)によって制御される2つの値が示されています。

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()の目標は、欠落データをチェックしながら次の引数を返すことです。NextArg()を使用すると、 'skip'はループをスキップして、フラグの解析を1つのライナーに抑えます。


0

Ercoのアプローチを拡張して、必須の位置引数とオプションの引数を許可しました。これらは、-d、-vなどの引数の前に置く必要があります。

位置引数とオプション引数は、それぞれPosArg(i)とOptArg(i、default)で取得できます。オプションの引数が見つかると、オプション(たとえば、-i)の検索の開始位置が1つ前に移動し、「予期しない」致命的エラーの発生を回避します。

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) 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.