Python | 自動化:argparse

Python
スポンサーリンク

概要(argparse は「コマンドライン引数をちゃんと扱うための道具」)

argparse は、
python script.py input.csv output.csv --date 2025-01-01
みたいな「コマンドラインから渡された文字列の引数」を、きれいに解析してくれる標準ライブラリです。

自動化でスクリプトが育ってくると、
「このパラメータだけ変えて動かしたい」「日付だけ変えたい」「モードを切り替えたい」
という場面が必ず出てきます。

そのときに、手作業でスクリプトを書くたびに書き換えるのではなく、
「引数で指定できるようにする」のが、argparse を使う意味です。

ここでは、

argparse の基本的な使い方
位置引数・オプション引数の違い
型変換・デフォルト値・選択肢制限
実用的な例(ファイル処理・日付指定バッチ)
設計で大事なポイント

を、初心者向けに丁寧にかみ砕いていきます。


基本の流れ(argparse でやることは3ステップ)

1. ArgumentParser を作る

まず、「このスクリプトはこんな引数を取りますよ」と宣言する器を作ります。

import argparse

parser = argparse.ArgumentParser(
    description="サンプルの CLI スクリプト"
)
Python

description は、--help をしたときに表示される「このツールは何をするか」の説明文です。
ちゃんと書いておくと、未来の自分が助かります。

2. どんな引数を受け取るかを定義する

次に、add_argument を使って、受け取る引数を宣言していきます。

例えば「名前を1つ受け取る」ならこうです。

parser.add_argument("name", help="挨拶する相手の名前")
Python

この1行で、

python greet.py 太郎

のような呼び出しをしたときに、「太郎」という文字列が name という引数として解釈されるようになります。

3. parse_args() で実データに変換する

最後に、実行時のコマンドラインから実際の引数を読み込みます。

args = parser.parse_args()
print(args.name)
Python

args は「属性を持つオブジェクト」で、args.name のようにして値を取り出せます。

ここまでが、argparse の最も基本的なパターンです。


位置引数とオプション引数(ここが一番の基礎)

位置引数(必須・順番で決まるやつ)

位置引数は、「書く順番で意味が決まる」「必須」の引数です。

parser.add_argument("input", help="入力ファイルパス")
parser.add_argument("output", help="出力ファイルパス")
Python

こう定義すると、呼び出しは次のようになります。

python tool.py in.csv out.csv

順番を入れ替えると意味が変わる(あるいはエラー)になるので、
「絶対に必要で、順番にも意味があるもの」に向いています。

「入力ファイル」「出力ファイル」「名前」「ID」など、
「ないと処理が成り立たないもの」を位置引数にするイメージです。

オプション引数(–xxx で指定するもの)

オプション引数は、--date--mode のように、名前付きで指定する引数です。

parser.add_argument(
    "--date",
    help="処理対象の日付(YYYY-MM-DD)。指定しない場合は昨日。",
    required=False
)
Python

呼び出しは、

python tool.py in.csv out.csv --date 2025-01-01

のようになります。

ポイントは、

必須ではなく、省略してもよい
名前付きなので順番に縛られにくい
「設定」「モード」「フィルター条件」などに向いている

というところです。


具体例1:挨拶スクリプトを argpase で CLI 化する

名前を位置引数で受けて、挨拶する

まずは超シンプルな例から。

# greet.py
import argparse

def parse_args():
    parser = argparse.ArgumentParser(
        description="名前を指定して挨拶する CLI"
    )
    parser.add_argument("name", help="挨拶する相手の名前")
    return parser.parse_args()

def main():
    args = parse_args()
    print(f"こんにちは、{args.name} さん")

if __name__ == "__main__":
    main()
Python

ターミナルから、

python greet.py 太郎

と打てば、

こんにちは、太郎 さん

と表示されます。

ここで一度 python greet.py --help を試してみてください。
自動で使い方が表示されます。description や help に書いた内容が、そのままヘルプに反映されているはずです。

日付をオプション引数で追加する

次に、日付を指定できるようにしてみます。

# greet_date.py
import argparse
from datetime import date

def parse_args():
    parser = argparse.ArgumentParser(
        description="名前と日付を指定して挨拶する CLI"
    )
    parser.add_argument("name", help="挨拶する相手の名前")
    parser.add_argument(
        "--date",
        help="挨拶の日付(YYYY-MM-DD)。省略時は今日。",
        required=False
    )
    return parser.parse_args()

def main():
    args = parse_args()

    if args.date:
        greeting_date = args.date
    else:
        greeting_date = date.today().isoformat()

    print(f"{greeting_date} 付で、こんにちは {args.name} さん")

if __name__ == "__main__":
    main()
Python

呼び出しは、

python greet_date.py 太郎
python greet_date.py 花子 --date 2025-01-01

のようになります。

ここで意識してほしいのは、

なくても動く情報(今回なら date)はオプション引数
必須の情報(name)は位置引数

に分ける、という設計の感覚です。


型・デフォルト値・選択肢(ここを使いこなすと一気に便利になる)

type で「文字列を数値などに変換」する

argparse で受け取った引数は、基本的に文字列です。
でも、数値として扱いたいときは、type= で型変換を自動化できます。

parser.add_argument(
    "--retries",
    type=int,
    default=3,
    help="リトライ回数(整数)"
)
Python

こうすると、

python tool.py --retries 5

と渡したときに、args.retries は整数 5 になります。

数字だけ受け付けたいときは、これで入力チェックにもなります。
文字列を渡すと argparse がエラーにしてくれるので、間違った使い方を早めに検知できます。

default で「指定がないときの値」を決める

さきほどの --retries にも書いていますが、
default= を指定すると、「引数が省略されたときに使う値」を決められます。

parser.add_argument(
    "--timeout",
    type=float,
    default=5.0,
    help="タイムアウト秒数(省略時は 5.0 秒)"
)
Python

こうしておけば、

python tool.py なら timeout は 5.0
python tool.py --timeout 10 なら timeout は 10.0

という風に、よく使う値をデフォルトとして埋め込んでおけます。

「ほとんどのケースではこの値でいいけれど、たまに変えたい」というパラメータは、
オプション引数+default で実装するのが鉄板です。

choices で「選べる値を制限する」

取りうる値が限られている場合(モードやフォーマットなど)、
choices を使うと入力ミスを防げます。

parser.add_argument(
    "--format",
    choices=["csv", "excel"],
    default="csv",
    help="出力形式(csv または excel)"
)
Python

こうすると、

python tool.py --format csv → OK
python tool.py --format pdf → エラー(使い方ミス)

になります。

CLI は「間違えたときにすぐ気づける」方が絶対に良いので、
選択肢が決まっている場合は積極的に choices を使ってください。


実用例2:CSV バッチを argpase でパラメータ化する

入力・出力ファイルとモードを引数にする

今度は、ちょっと実務寄りの CSV ツールをイメージしてみます。

やりたいことは、

入力 CSV を読み込む
何らかの加工をする
出力 CSV または Excel に保存する

というバッチです。

これを CLI として設計すると、

入力ファイル(必須)
出力ファイル(必須)
出力形式(csv / excel のどちらか。省略時は csv)

くらいを引数にしたくなります。

# csv_batch.py
import argparse
from pathlib import Path

def parse_args():
    parser = argparse.ArgumentParser(
        description="CSV を読み込んで加工し、CSV または Excel で出力するバッチ"
    )
    parser.add_argument("input", help="入力 CSV ファイルパス")
    parser.add_argument("output", help="出力ファイルパス")
    parser.add_argument(
        "--format",
        choices=["csv", "excel"],
        default="csv",
        help="出力形式(csv または excel)。省略時は csv。"
    )
    return parser.parse_args()

def process_file(input_path: Path, output_path: Path, fmt: str):
    import csv

    rows = []
    with input_path.open("r", encoding="utf-8") as f:
        reader = csv.DictReader(f)
        for row in reader:
            row["processed"] = "yes"
            rows.append(row)

    if fmt == "csv":
        with output_path.open("w", encoding="utf-8", newline="") as f:
            writer = csv.DictWriter(f, fieldnames=rows[0].keys())
            writer.writeheader()
            writer.writerows(rows)
    else:
        import pandas as pd
        df = pd.DataFrame(rows)
        df.to_excel(output_path, index=False)

def main():
    args = parse_args()
    input_path = Path(args.input)
    output_path = Path(args.output)
    process_file(input_path, output_path, args.format)

if __name__ == "__main__":
    main()
Python

この CLI は次のように使えます。

python csv_batch.py data/input.csv data/output.csv
python csv_batch.py data/input.csv data/output.xlsx --format excel

ここで深掘りしたいのは、

argparse は「文字列の世界」。Path や bool や date などへの変換は main で行う
処理本体(process_file)は、「Python 内部の型」を受け取る純粋な関数にしておく

という設計方針です。

こうしておくと、将来「Web から呼ばれる」「別のバッチから呼ばれる」など、
CLI 以外の文脈でも簡単に再利用できます。


実用例3:日付指定バッチ(–date をうまく扱う)

「指定がなければ昨日」を実装する典型パターン

日次バッチでは、「対象日」が非常に重要な引数になります。

やりたいのは、

--date が指定されたらその日付を使う
指定されなければ「昨日」を使う

という動きです。

# daily_job.py
import argparse
from datetime import date, timedelta

def parse_args():
    parser = argparse.ArgumentParser(
        description="日付ごとのデータを処理する日次バッチ"
    )
    parser.add_argument(
        "--date",
        help="処理対象日(YYYY-MM-DD)。指定がなければ昨日。",
        required=False
    )
    return parser.parse_args()

def get_target_date(date_str: str | None) -> date:
    if date_str:
        return date.fromisoformat(date_str)
    else:
        return date.today() - timedelta(days=1)

def run_for_date(target_date: date):
    print(f"{target_date} のデータを処理します")
    # 実際の処理を書く

def main():
    args = parse_args()
    target_date = get_target_date(args.date)
    run_for_date(target_date)

if __name__ == "__main__":
    main()
Python

このコードの設計で大事な点は、

CLI 層(parse_args)は「文字列を受け取るだけ」
ビジネスロジック層(get_target_date, run_for_date)は、ちゃんとした型(date)で動く

という分離ができていることです。

この感覚を持てると、argparse は「外側の殻」であって、
「中身のロジック」と適度な距離を置いて書けるようになります。


設計で本当に大事なポイントを深掘りする

main とロジックを分ける(テスト・再利用のため)

argparse を書き始めると、つい main の中に全部の処理を書きがちです。

def main():
    parser = ...
    args = parser.parse_args()
    # ここから先にロジックを全部書いてしまう
Python

これをやると、次のような弊害が出ます。

他の Python コードから処理だけ呼び出したいときに再利用しづらい。
単体テストを書きにくい。
CLI の変更(引数の追加・名前変更)とロジックの変更がごちゃ混ぜになる。

避けるためには、

引数パース専用の関数(parse_args)を作る
CLI から渡ってきた文字列を「ちゃんとした型」に変換してから、ロジック関数に渡す

という分離を徹底することが大事です。

エラーメッセージと終了コードを意識する

ユーザーの入力ミス(存在しないファイルパスなど)は、
きちんとメッセージを出して終了コードを 1 にするのが親切です。

import sys
from pathlib import Path

def main():
    args = parse_args()
    input_path = Path(args.input)
    if not input_path.exists():
        print(f"入力ファイルが見つかりません: {input_path}", file=sys.stderr)
        sys.exit(1)
    # 正常処理
Python

こうしておくと、

人間が見たときはエラーメッセージで気づける
他のスクリプトやバッチから呼んだときは、「終了コードで失敗を検知」できる

という状態になります。

ヘルプ(description・help)を真面目に書く

argparse の大きなメリットの一つが「勝手にヘルプを作ってくれること」です。
その力を十分に使うために、

parser = argparse.ArgumentParser(description=”…”)
add_argument(…, help=”…”)

には、できるだけちゃんと説明を書くのがおすすめです。

何をするツールなのか
引数は何を意味しているのか
どんなフォーマットで渡すべきか(例:YYYY-MM-DD)

を短くてもいいので、言葉にしておくと、
3ヶ月後・半年後の自分が見たときに、非常に助かります。


まとめ(argparse は「スクリプトをツールに昇格させる」鍵)

Python 自動化における argparse の役割をまとめると、こうなります。

argparse は、コマンドライン引数を簡潔・安全に扱うための標準ライブラリで、--help 付きの「ちゃんとした CLI」を作れる。
位置引数は「絶対必要な情報」、オプション引数は「設定・モード・条件」のような任意情報に使い分ける。
type・default・choices を使うと、引数の型変換・デフォルト値・入力制限を簡潔に書けて、使い方ミスを減らせる。
日付・ファイルパス・モードを引数化することで、スクリプトが「何度でも条件を変えて使えるツール」に変わる。
引数パース(外側)とロジック(内側)を分離し、ヘルプとエラーメッセージを丁寧に整えることが、長く使える自動化ツールの土台になる。

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