Pythonでコマンドライン引数を処理する方法としてsysモジュールとargparseモジュールが標準で用意されています。(argparseはPython 3.2以降で利用可能)
それぞれの違いと、私がsysよりargparseを使うべきと考える理由について解説します。
sysモジュールの使い方
sysモジュールは以下のように、sys.argvにアクセスすることで引数を取得できます。
import sys
print(sys.argv[0]) # 実行ファイル名(str型)
print(sys.argv[1]) # 1つ目の引数(str型)
print(sys.argv[2]) # 2つ目の引数(str型)
[0]には実行ファイル名が入っており、[1]以降にはコマンドライン引数が順次収納されています。型はいずれもstr型です。
リストとしてシンプルに扱えるため、小規模なプログラムで有効な方法と言えます。
argparseモジュールの使い方
一方argparseモジュールは位置引数だけではなく–optionのような形式のオプションを扱えるほか、それぞれの引数に型やヘルプを設定することができるなど非常に多機能です。
import argparse
parser = argparse.ArgumentParser(description="位置引数とオプション引数を追加する例")
# 位置引数(必須)
parser.add_argument('hoge', help='必須の位置引数')
# オプション引数(任意指定、デフォルト値あり)
parser.add_argument('--option', help='任意で指定するオプション', default='fuga')
# オプション引数(フラグ形式)
parser.add_argument('--flag', action='store_true', help='--flagを指定することで有効になる')
args = parser.parse_args()
argparseを使うべきと考える理由
sysモジュールではとにかく外部から引数を与えればスクリプト内で取得できましたが、argparseモジュールではadd_argument()を用いてそのスクリプトがどのような引数を受け付けるかを事前に設計することになります。
複雑な引数を持つスクリプトを作成する場合や、ヘルプを設定できることから他者に公開するスクリプト(一般公開したり、開発チーム内で他の人に使ってもらうスクリプト等)はargparseが向いていると思います。
ただ私はテスト用に作るごく小規模なプログラムを除き、なるべくargparseで実装するのが良いと考えています。
理由としてはスクリプト実行のタイミングで型や使い方の不正を検出できるからです。
argparseの場合、間違った型を指定されたり、オプション名の指定ミスなどを実行時のタイミングで検出することが可能で、その場合スクリプト自体がエラーを返しそれ以上先へ処理を進めないようにすることができます。
sysモジュールの場合、間違いを含んだsys.argv[n]にアクセスして処理したタイミングでしか検出することができず、適切な例外処理を行わなければ意図せずスクリプトが停止する可能性もあります。特定の条件でしか引数sys.argv[n]にアクセスされないような場合、テストが不足すればそこに潜むバグの発見が遅れるリスクもあります。
もちろんsysモジュールでもスクリプトの初期段階で十分なチェック処理を入れることで対策は可能ですが、手動でそれらを実装するのであればargparseモジュールを使った方が確実です。
Pythonのようなインタープリター型、動的型付け言語は基本的にエラーの発見が実行時に該当コードが読み込まれたタイミングになるため、それをスクリプト開始段階でまとめてチェックできることはテストの負担軽減に繋がると考えられます。
外部から入力を受け付ける部分はバグの原因になりやすく、場合によっては脆弱性など致命的なバグに繋がる可能性もあります。argparseを使っても全てが防げるわけではありませんが、可能な限り高度なモジュールを使って処理を行うべきだと思います。
コメント