PR

【簡単!】Pythonで「オプション機能」を実装する方法

OSS開発

この記事ではPythonで「--help」などのオプション機能を実装する方法を解説します。

-lsr」のように複数のオプションを組み合わせられるようにすることが特徴です。

WordPressブロガーの方必見! 外出先でもブログ執筆作業がはかどる、 Ankerの大容量モバイルバッテリー をご紹介します。

Pythonファイルにオプションを実装する

目標は、以下のようにPythonファイルにオプションを渡して実行できるようにすることです。渡すオプションは、「--」でも「-」でも対応できるようにします。

Bash
$ python hoge.py -オプション

以下はオプション機能を実装したPythonファイルのテンプレートです。

Python
import sys

def usage():
    print("""
Usage: command [options]

Description: [ファイルの説明]

Features: [ファイルの説明]

Arguments: [引数の説明]

Options:
    -h|--help           Display help
    -x|--option         [オプションの説明]



""")

options = set()  # 使用されたオプションを格納するための集合
i = 1 # 始まりは0ではなく、1とすること
while i < len(sys.argv):
    if sys.argv[i] in ["-h", "--help"]:
        # 引数が「-h」もしくは「--help」だったら「usage()」を実行して正常終了する
        usage()
        sys.exit(0) # 正常終了する
    elif sys.argv[i] in ["--オプション"]:
        options.update({sys.argv[i][2:]}) # 集合にオプションを追加する
        i += 1 # 処理を実行した後は、次の引数を処理するためにiに1を足す
    elif sys.argv[i].startswith("--"):
        print("\033[91mError: Invalid Option\n無効なオプションです。--help を使用してください。\033[0m")
        sys.exit(1)  # 異常終了する
    elif sys.argv[i].startswith("-"):
        # オプションが複数組み合わさっている場合も考慮して、一文字ずつ分割
        options.update(sys.argv[i][1:])
        i += 1
    else:
        i += 1 # ハイフンが先頭に無い引数を無視する

if {"短いオプション1"} <= options or {"長いオプション1"} <= options:
    [処理]
if {"短いオプション2"} <= options or {"長いオプション2"} <= options:
    [処理]
if {"短いオプション3"} <= options or {"長いオプション3"} <= options:
    [処理]


上記のファイルが完成するように手順を1つずつ解説します。

1.「sys」をインポートする

オプションを渡すためには、Python標準搭載の「sys」パッケージを使用します。

Python
import sys

2.「sys.argv」で引数を全て取得する

sysをインポートすると、sys.argvが使えるようになります。 これを使うと自動で引数全てを取得できます

sys.argvという配列になっているので、それをwhile文で1つ1つ取得します。

Python
i = 1 # 始まりは0ではなく、1とすること
while i < len(sys.argv):
    [処理]

whileは引数の数だけ処理を行います。ポイントは「i」を1にすることです。sys.argv[0]ファイルパスを格納していますが、今回は必要ないためです。sys.argv[1]から引数が順次格納されます。

この引数の内、ハイフン(-)が先頭にあるものがオプションとなります。

3.「–help」オプションを作成する

Pythonファイルにオプションを渡せるようになったので、まずは「--help」オプションを作成します。 下記のような「usage()」関数を作成します。

Python
def usage():
    print("""
Usage: command [options]

Description: [ファイルの説明]

Features: [ファイルの説明]

Arguments: [引数の説明]

Options:
    -h|--help           Display help
       --help_jp        Display help in Japanese
    -x|--option        [オプションの説明]



""")

この関数は、実行するとターミナルにヘルプ画面を表示するように設計されています。

関数を記述したら、while文の中で if sys.argv[i] in ["-h", "--help"]:とします。これで -h」もしくは「--help」のオプションが渡された時に、処理を実行する ようになります。

処理の内容は「usage()」の実行と「sys.exit(0)」の実行です。 sys.exit(0)は正常終了でプログラムを終わらせるコードです。つまり、「-h」と「--help」はヘルプ画面を表示してプログラムを終了させるオプションということになります。

Python
# 引数が「-h」もしくは「--help」だったら「usage()」を実行して正常終了する
i = 1
while i < len(sys.argv):
    if sys.argv[i] in ["-h", "--help"]: 
        usage()
        sys.exit(0)

4.長いオプションを作成する

--help」が出来たので、実装したいオプションを作成していきます。

まずは長いオプションを作成します。長いオプションとは--オプション」とハイフンが二個連続で始まる引数のことです。

helpとは異なり、ここから先のオプションはその場で実行するのではなく、一旦「set型(集合)」に格納します。set型は「optisons」という変数に入れます。

Python
options = set()

sys.argv[i] in ["--オプション"]:」で引数が長いオプションに合致した場合、「options.update({sys.argv[i][2:]})」でset型に格納します。

Python
options = set()  # 使用されたオプションを格納するための集合
i = 1
while i < len(sys.argv):
    elif sys.argv[i] in ["--オプション"]:
        options.update({sys.argv[i][2:]}) # 集合にオプションを追加する
        i += 1 # 処理を実行した後は、次の引数を処理するためにiに1を足す

「set型.update(値)」とすれば、集合に値を追加できます。ポイントは渡す値を「{}」で囲うことです。 例えば、「--split」オプションを渡すとします。{sys.argv[i][2:]}{}で囲んでいれば{'split'}のように格納されることになりますが、囲わなければ以下のように1文字ずつ格納されることになります。

Python
{'s', 'p', 'i', 'l', 't'}

処理を実行した後は、次の引数を処理するためにiに1を足すことを忘れないでください

5.無効なオプションへの処理を設定する

余計なトラブルを減らすために、こちらが想定していない長いオプションに対する処理を設定します。

引数が「--」から始まり、かつどの長いオプションにも当てはまらない条件を作ります。この時に役立つのが「startswith("文字")」メソッドです。引数に渡した文字から始まる全ての文字列が条件に合致します

Python
while i < len(sys.argv):
    elif sys.argv[i].startswith("--"):
        print("\033[91mError: Invalid Option\n無効なオプションです。--help を使用してください。\033[0m")
        sys.exit(1) # 異常終了する

エラーメッセージが出るようにします。その後「sys.exit(1)」を実行し、異常終了でプログラムを終わらせましょう。

6.短いオプションを作成する

短いオプションを作成します。短いオプションは「startswith("文字")」を使用し、ハイフンから始まる全てのオプションを格納するようにします。

Python
options = set()  # 使用されたオプションを格納するための集合
i = 1
while i < len(sys.argv):
    elif sys.argv[i].startswith("-"):
        # オプションが複数組み合わさっている場合も考慮して、一文字ずつ分割
        options.update(sys.argv[i][1:])
        i += 1
    else:
        i += 1 # ハイフンが先頭に無い引数を無視する

無効オプションを設定できないのですが、ここは割り切ります。

なぜ、このような条件にしているかというと、オプションを組み合わせられるようにしたいからです。

たとえば、「-l」と「-s」と「-r」を組み合わせて-lsr」だけで実行できるようになります。

Bash
$ python hoge.py -lsr

そこで先程の「set型.update()」を使用します。長いオプションで{}で囲うことを強調しましたが、今度は逆に囲いません。こうすることで、ハイフン以下の文字が1文字ずつ集合に格納されることになります。

Python
{'l', 's', 'r'}

最後に、「else:」で頭にハイフンが一切ついていない引数を無視すれば、オプション機能は完成です。

7.オプションごとに処理を振り分ける

set型は順番は関係ないため、該当のオプションが集合にあるかどうかだけ判定します。 上から、順にif文で処理を書いていきます。

Python
if {"短いオプション1"} <= options or {"長いオプション1"} <= options:
    [処理]
if {"短いオプション2"} <= options or {"長いオプション2"} <= options:
    [処理]
if {"短いオプション3"} <= options or {"長いオプション3"} <= options:
    [処理]


or」を使用することで、短いオプションと長いオプションで同じ処理をさせることができます。 以下は、「 -b--no-break を渡すと改行を削除するオプション」です。

Python
# -b か --no-break を渡すと改行を削除するオプション
if {"b"} <= options or {"no-break"} <= options:
    txt = "".join(txt.splitlines())

PyPIにアップロードしたいなら?

オプション付きのPythonファイルを作成したら、多くの人に使ってもらいたいと思うかもしれません。Pythonでは「PyPI」にアップロードすることで、OSに関係なくどんなPCにもインストールできるようになります。

PyPIへのアップロード方法については、以下の記事をご参照ください。

まとめ

この記事では、「--help」などのオプション機能をPythonファイルに実装する方法を解説しました。

紹介した方法の特徴は 「オプションの組み合わせ」 ができることです。

是非開発の際に、参考にして頂けたら幸いです。

タイトルとURLをコピーしました