komeの備忘録

東大理系大学院生の技術ブログ。たまに趣味。

pythonでコマンドライン引数をargparseでさくっと処理する

https://www.komee.org/entry/2018/10/27/120000www.komee.org

前回のこの記事を書いたときに、コマンドライン引数を処理するために使ったargparseがめっちゃ便利で感動したので記事にした。

コマンドライン引数の処理

sample.pyというスクリプトを実行する時、一般に次のように実行する。

$ python sample.py

次に、sample.pyに-aオプションや-bオプションが使えるとしたら次のようになると思う。

$ sample.py -a hoge -b gege

一般的にこういう実装をしようとしたときは、sys.argvを受け取ってsplitして条件分けしてある引数が存在したらそれに対応する操作をして、、、みたいな感じになると思われる。

簡単に言うと、実装がめんどくさい
(私の実装力が低いだけというのもあるが)

こんな時に、pythonであれば、標準実装のargparseというライブラリをインポートすると、さくっと実装できてしまうのである!

まずはargparseの説明をする。

argparseとは

argparseモジュールは、ユーザフレンドリなコマンドラインインタフェースの作成を簡単にします。プログラムがどんな引数を必要としているのかを定義すると、argparseがsys.argvからそのオプションを解析する方法を見つけ出します。argparseモジュールは自動的にヘルプと使用方法メッセージを生成し、ユーザが不正な引数をプログラムに指定したときにエラーを発生させます。 https://docs.python.jp/3/library/argparse.。html

簡単に言うと、コマンドライン引数の処理を簡単に実装できるライブラリである。
特筆すべきは、実装と同時にヘルプページと使用方法のメッセージも勝手に作成してくれるということである!

先に実装した前回の記事を例に説明すると、-h引数をスクリプトに渡したときの処理を勝手に作ってくれるのである。

$ python unimove.py -h
usage: unimove.py [-h] [-f FRAME] [-s START] input

positional arguments:
  input                 Absolute/relative path to input file

optional arguments:
  -h, --help            show this help message and exit
  -f FRAME, --frame FRAME
                        Number of interval frame
  -s START, --start START
                        Time of union start

こんないい感じの使い方とヘルプページは、私は一切実装していない。

使い方

では具体的な実装方法を説明する。
私の以前実装したコードを例に、必要な箇所のみを抜粋して説明する。

必要なライブラリは、argparse。今回は、from argparse import ArgumentParserとしてインポートした。

from argparse import ArgumentParser

def get_option():
    argparser = ArgumentParser()
    argparser.add_argument('input', type=str, help='Absolute/relative path to input file')
    argparser.add_argument('-f', '--frame', type=int, default=3, help='Number of interval frame')
    argparser.add_argument('-s', '--start', type=int, default=0, help='Time of union start')
    args = argparser.parse_args()
    return args

if __name__ == '__main__':
    args = get_option()
    
    inputFile = args.input 
    frame = args.frame
    startTime = args.start
    unimove(inputFile, frame, startTime)

オブジェクトの定義

argparser = ArgumentParser()

今回、引数処理をする関数はget_option()として定義し、この中ですべての引数処理を行うようにした。
get_option()の中では最初にまずArgumentParser()オブジェクトの定義をし、argparserとする。

引数の定義

argparser.add_argument('input', type=str, help='Absolute/relative path to input file')
argparser.add_argument('-f', '--frame', type=int, default=3, help='Number of interval frame')
argparser.add_argument('-s', '--start', type=int, default=0, help='Time of union start')

argparser.add_argument()で引数をargparserに追加していく。
この時、引数の名前に--をつけたものはオプション引数として定義され、省略ができるようになる。
よって今回の場合は、inputが自動的に必須の引数となり、それ以外の--frame--startは省略可能となる。

また、後々に引数の値をプログラム内で呼び出す際には、基本的にはここで定義した名前が属性名となり使われる。このとき、--frameとして定義した名前は、属性名はframeとなる。

typeで指定した型で値をパースして保持し、省略された場合はdefaultにセットした値が使われるのはなんとなくわかるだろう。
また、helpに指定された部分は、このプログラムを-hをつけて実行した場合に表示されるhelpページの引数の説明のところに表示される。

つまり、完成したプログラムを使用して、ヘルプを表示すると先程のヘルプが爆誕する。

他にもadd_argumentは様々なオプション引数があり、詳しくは公式リファレンスを参照するといい。

16.4. argparse — Parser for command-line options, arguments and sub-commands — Python 3.6.7 documentation

引数に定義された値の呼び出し

ここまでに定義されたオブジェクトは、argparser.parse_args()として、mainに返す。

def get_option():
.
.
    args = argparser.parse_args()
    return args

返されたargsの中に、引数情報が格納されており、これを先に定義した属性で呼び出すことで、プログラム内で用いることができる。

if __name__ == '__main__':
    args = get_option()
    
    inputFile = args.input 
    frame = args.frame
    startTime = args.start
    unimove(inputFile, frame, startTime)

まとめ

やはり、特にhelpが勝手に生成されるのは非常に便利だなぁと思った。 加えて面倒な引数処理もいい感じにやってくれて、プログラムの中で使うに当たって非常に使いやすくなったと思う。今後のヘビロテが確定した。

参考にしたサイト

16.4. argparse — Parser for command-line options, arguments and sub-commands — Python 3.6.7 documentation