Python の argparse で相互排他オプションを設定する
コマンドラインツールでは、同時に指定してはいけないオプションの組み合わせがある。たとえば --verbose と --quiet は意味が矛盾するし、--json と --csv のように出力形式を排他的に選ばせたい場面も多い。Python の argparse では add_mutually_exclusive_group() を使って、こうした相互排他のオプションを定義できる。
基本的な使い方
add_mutually_exclusive_group() はパーサーに対して呼び出し、返されたグループオブジェクトに対して add_argument() を追加していく。
import argparse
parser = argparse.ArgumentParser(description="ログレベル設定")
group = parser.add_mutually_exclusive_group()
group.add_argument("--verbose", action="store_true", help="詳細出力")
group.add_argument("--quiet", action="store_true", help="出力を抑制")
args = parser.parse_args()
if args.verbose:
print("詳細モード")
elif args.quiet:
print("静粛モード")
else:
print("通常モード")この定義により、--verbose と --quiet を同時に指定するとエラーが発生する。
$ python app.py --verbose
詳細モード
$ python app.py --quiet
静粛モード
$ python app.py --verbose --quiet
usage: app.py [-h] [--verbose | --quiet]
app.py: error: argument --quiet: not allowed with argument --verboseエラーメッセージは argparse が自動生成してくれるため、自分でバリデーションを書く必要がない。ヘルプの usage 行でも [--verbose | --quiet] とパイプ記号で排他関係が示される。
required=True で必須にする
デフォルトでは、排他グループ内のどのオプションも指定しなくて構わない。しかし「どちらか一方は必ず選んでほしい」という場合もある。そのときは required=True を渡す。
import argparse
parser = argparse.ArgumentParser(description="出力形式の指定")
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--json", action="store_true", help="JSON 形式で出力")
group.add_argument("--csv", action="store_true", help="CSV 形式で出力")
args = parser.parse_args()こうすると、どちらも指定しなかった場合にエラーになる。
$ python export.py
usage: export.py [-h] (--json | --csv)
export.py: error: one of the arguments --json --csv is requiredusage 行の括弧が角括弧 [] から丸括弧 () に変わり、必須であることが視覚的にもわかる。
どちらも指定しなくてよい。usage 表示は [--json | --csv]
どちらか一方の指定が必須。usage 表示は (--json | --csv)
複数の排他グループ
1 つのパーサーに複数の排他グループを設けることもできる。出力形式とログレベルをそれぞれ独立した排他グループにする例を見てみよう。
import argparse
parser = argparse.ArgumentParser(description="データ処理ツール")
# 出力形式の排他グループ
fmt_group = parser.add_mutually_exclusive_group()
fmt_group.add_argument("--json", action="store_true", help="JSON 出力")
fmt_group.add_argument("--csv", action="store_true", help="CSV 出力")
# ログレベルの排他グループ
log_group = parser.add_mutually_exclusive_group()
log_group.add_argument("--verbose", action="store_true", help="詳細ログ")
log_group.add_argument("--quiet", action="store_true", help="ログ抑制")
args = parser.parse_args()
print(args)この場合、--json と --csv の間、--verbose と --quiet の間はそれぞれ排他だが、--json と --verbose のようにグループをまたいだ組み合わせは自由に指定できる。
$ python tool.py --json --verbose
Namespace(json=True, csv=False, verbose=True, quiet=False)
$ python tool.py --json --csv
error: argument --csv: not allowed with argument --jsonstore_true 以外の排他オプション
排他グループは store_true 以外の引数でも使える。値を受け取るオプション同士を排他にするケースも珍しくない。
import argparse
parser = argparse.ArgumentParser(description="認証方法の選択")
auth_group = parser.add_mutually_exclusive_group(required=True)
auth_group.add_argument("--token", type=str, help="APIトークンで認証")
auth_group.add_argument("--user", type=str, help="ユーザー名で認証")
args = parser.parse_args()
if args.token:
print(f"トークン認証: {args.token}")
else:
print(f"ユーザー認証: {args.user}")--token と --user はどちらも文字列を受け取るが、同時には指定できない。認証方法のように「手段は複数あるが選べるのは 1 つだけ」という設計に適している。
排他グループは引数の整合性をパーサーレベルで保証できるため、バリデーションコードを減らし、ヘルプメッセージでも制約を明示できる。オプションが増えてきたら、論理的にぶつかる組み合わせがないか確認し、積極的に活用するとよいだろう。












