👋

clickを使ってPythonのコマンドライン引数をきれいにしよう!

に公開

今回は、Pythonできれいなコマンドラインインターフェースを実装できるclickについて紹介してみようと思います。

clickとは?

clickとはPythonできれいなコマンドラインインターフェースを実装するためのライブラリです。その名前はCommand Line Interface Creation Kitの頭文字をとったようです。レポジトリは以下になります。

https://github.com/pallets/click

clickはコマンドラインツールを素早く実装できることに注力しており、従来のsysargparseを利用したものと比べて格段に実装難易度が下がっていると思います。

実際に使ってみた

まずは標準ライブラリのsysargparseを使ったパースと比べてどれほど使いやすいか比較してみましょう。

今回比較するために実装する対象は以下に設定します。

  • 第一引数に文字列を受け取る
  • 第二引数に数字を受け取る
  • 第二引数で指定された回数だけ第一引数の文字列を表示する

sysで実装

sysで実装すると以下のようになります。

sys_impl.py
import sys

def main():
    if len(sys.argv) != 3:
        raise Exception("Please specify argument properly")

    text = sys.argv[1]
    _repeat_num = sys.argv[2]
    try:
        repeat_num = int(_repeat_num)
    except:
        raise Exception("Please set second argument as number")

    print(text * repeat_num)


if __name__ == "__main__":
    main()

まず、今回のコードは以下のように呼び出されることを想定しています。

python sys_impl.py hoge 2

sys.argvから引数を取得できますが、その値の中には呼び出したPythonコード名(この場合sys_impl.py)が含まれるので、sys.argvは合計3つの要素を持つ必要があります。その確認をするために以下のチェックを入れています。

if len(sys.argv) != 3:
    raise Exception("Please specify argument properly")

次に、引数の内容をパースしていきます。繰り返す回数については文字列として数値を受け取りそれをint型にキャストする必要がありますが、数値以外の入力があり得るのでそのチェックを行っています。

text = sys.argv[1]
_repeat_num = sys.argv[2]
try:
    repeat_num = int(_repeat_num)
except:
    raise Exception("Please set second argument as number")

すべてのチェックが問題なければ文字列を繰り返すだけです。先ほどの例を実行すると以下のようになります。

python sys_impl.py hoge 2
hogehoge

argparseで実装

それでは次はargparseで実装してみましょう。

argparse_impl.py
import argparse

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('text', type=str)
    parser.add_argument('repeat_num', type=int)
    args = parser.parse_args()

    print(args.text * args.repeat_num)


if __name__ == "__main__":
    main()

argparseを利用すると型チェックも合わせて対応できるので便利です。ここでは第一引数をtext、第二引数をrepeat_numという名前で取得し、先ほどと同様に繰り返し表示させます。実行すると以下のように先ほどと同じ結果が得られます。

python argparse_impl.py hoge 2
hogehoge

clickで実装

それでは今回のテーマであるclickで実装してみましょう。

インストール方法についてですが、pip install clickでインストール可能です。

インストールが終わったら具体的な実装をしてみましょう。

click_impl.py
import click

@click.command()
@click.argument("text", type=str)
@click.argument("repeat_num", type=int)
def main(text, repeat_num):
    print(text * repeat_num)

if __name__ == "__main__":
    main()

clickでは主にデコレータを用いて定義をしていきます。実際の定義の仕方はargparseに似ていますが、デコレータで指定した名前と関数の引数を一致させることで、シームレスに呼び出し可能な状態で関数を実装できるのが特徴です。こちらも実行すると先ほどと同じ結果が得られます。

python click_impl.py hoge 2
hogehoge

clickの便利な機能

個人的に便利な機能と思うのはサブグループ機能です。
例えば一つのPythonファイルでJPG画像用のコマンドPNG画像用のコマンドを分けて実装したい場合などに、もしそれぞれで引数が異なる場合に役立ちます(同じ引数なら一つのコマンドで作った方がいいです)。例えば以下のように実装するとグループが作れます。

group.py
import click

@click.group()
def cli():
    pass

@cli.command("for-jpg")
@click.argument("jpg-option")
def for_jpg(jpg_option):
    print(jpg_option)


@cli.command("for-png")
@click.argument("png-option")
def for_png(png_option):
    print(png_option)


if __name__ == "__main__":
    cli()

これで準備完了です。まずは何も指定しないで呼び出してみましょう。

python group.py

Usage: group.py [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  for-jpg
  for-png

すると以下のようにコマンドがfor-jpgfor-pngがあると指定してくれます。グループのコマンドを呼び出すにはpython group.py for-jpgのように続けてグループ内のコマンド名を指定します。試しに実行してみると

python group.py for-jpg

Usage: group.py for-jpg [OPTIONS] JPG_OPTION
Try 'group.py for-jpg --help' for help.

Error: Missing argument 'JPG_OPTION'.

のように表示され、for-jpgに向けたオプションが表示されます。このようにすることでコマンドレベルでコードの条件分岐を簡単に設定することができます。

まとめ

今回はPythonのコマンドラインインターフェースのためのclickというライブラリを紹介しました。公式ドキュメントではより詳しいチュートリアルが用意されておりますので、コマンドラインでうまく実装したいなっと思った方はぜひ参考にしてください!

Discussion