3.6 argparse - CLI 介面
3.6 argparse - CLI 介面
argparse 是 Python 標準庫中用於建立命令列介面(CLI)的模組。它能自動生成幫助訊息、處理各種參數類型,並進行輸入驗證。
基本用法
最簡單的 CLI
1import argparse
2
3parser = argparse.ArgumentParser(description="我的程式")
4parser.add_argument("filename", help="要處理的檔案")
5args = parser.parse_args()
6
7print(f"處理檔案: {args.filename}")執行:
1$ python script.py myfile.txt
2處理檔案: myfile.txt
3
4$ python script.py --help
5usage: script.py [-h] filename
6
7我的程式
8
9positional arguments:
10 filename 要處理的檔案
11
12options:
13 -h, --help show this help message and exit參數類型
位置參數(Positional Arguments)
必須提供的參數:
1parser.add_argument("filename")
2# 使用: python script.py myfile.txt可選參數(Optional Arguments)
使用 - 或 -- 開頭:
1parser.add_argument("-v", "--verbose", action="store_true")
2parser.add_argument("-o", "--output", default="output.txt")
3# 使用: python script.py -v -o result.txt布林旗標
1# store_true:出現時為 True
2parser.add_argument("--debug", action="store_true")
3
4# store_false:出現時為 False
5parser.add_argument("--no-cache", action="store_false", dest="cache")實際範例:Hook 驗證器
來自 .claude/lib/hook_validator.py:
1def main():
2 """命令行介面"""
3 parser = argparse.ArgumentParser(
4 description="Hook 合規性驗證工具",
5 formatter_class=argparse.RawDescriptionHelpFormatter,
6 epilog="""
7使用範例:
8 # 驗證單一 Hook
9 python hook_validator.py .claude/hooks/my-hook.py
10
11 # 驗證所有 Hook
12 python hook_validator.py --all
13
14 # 輸出 JSON 格式
15 python hook_validator.py --all --json
16
17 # 自訂 Hook 目錄
18 python hook_validator.py --all --dir .claude/hooks
19 """
20 )
21
22 parser.add_argument(
23 "hook_path",
24 nargs="?",
25 help="Hook 檔案路徑(相對或絕對)"
26 )
27 parser.add_argument(
28 "--all",
29 action="store_true",
30 help="驗證所有 Hook 檔案"
31 )
32 parser.add_argument(
33 "--dir",
34 help="自訂 Hook 目錄路徑(預設 .claude/hooks)"
35 )
36 parser.add_argument(
37 "--json",
38 action="store_true",
39 help="輸出 JSON 格式"
40 )
41 parser.add_argument(
42 "--strict",
43 action="store_true",
44 help="嚴格模式:將 warning 視為 error"
45 )
46
47 args = parser.parse_args()
48
49 # 根據參數執行不同邏輯
50 if args.all:
51 results = validate_all_hooks(hooks_dir=args.dir)
52 elif args.hook_path:
53 results = [validate_hook(args.hook_path)]
54 else:
55 parser.print_help()
56 sys.exit(1)
57
58 # 輸出結果
59 if args.json:
60 print(json.dumps(output, ensure_ascii=False, indent=2))
61 else:
62 print(format_validation_report(results))常用參數選項
nargs - 參數數量
1# 單一值(預設)
2parser.add_argument("filename")
3
4# 可選(0 或 1)
5parser.add_argument("output", nargs="?", default="out.txt")
6
7# 零或多個
8parser.add_argument("files", nargs="*")
9
10# 一或多個
11parser.add_argument("files", nargs="+")
12
13# 固定數量
14parser.add_argument("point", nargs=2, type=int) # 需要兩個整數type - 型別轉換
1# 整數
2parser.add_argument("--count", type=int, default=10)
3
4# 浮點數
5parser.add_argument("--ratio", type=float)
6
7# 檔案路徑
8from pathlib import Path
9parser.add_argument("--config", type=Path)choices - 限制選項
1parser.add_argument(
2 "--format",
3 choices=["json", "yaml", "text"],
4 default="text",
5 help="輸出格式"
6)default - 預設值
1parser.add_argument("--timeout", type=int, default=30)
2parser.add_argument("--verbose", action="store_true") # 預設 Falserequired - 強制必填
1parser.add_argument("--config", required=True)dest - 屬性名稱
1parser.add_argument("--no-cache", action="store_false", dest="use_cache")
2# args.use_cache 而非 args.no_cache實際範例:Markdown 連結檢查器
來自 .claude/lib/markdown_link_checker.py:
1def main():
2 """命令行介面"""
3 parser = argparse.ArgumentParser(
4 description="Markdown 連結檢查工具",
5 formatter_class=argparse.RawDescriptionHelpFormatter,
6 epilog="""
7使用範例:
8 # 檢查單一文件
9 python markdown_link_checker.py docs/README.md
10
11 # 檢查整個目錄
12 python markdown_link_checker.py --dir .claude/methodologies/
13
14 # JSON 輸出
15 python markdown_link_checker.py --dir docs/ --json
16
17 # 只檢查當前目錄(不遞迴)
18 python markdown_link_checker.py --dir docs/ --no-recursive
19 """
20 )
21
22 parser.add_argument(
23 "file_path",
24 nargs="?",
25 help="Markdown 檔案路徑"
26 )
27 parser.add_argument(
28 "--dir",
29 help="要檢查的目錄路徑"
30 )
31 parser.add_argument(
32 "--json",
33 action="store_true",
34 help="輸出 JSON 格式"
35 )
36 parser.add_argument(
37 "--no-recursive",
38 action="store_true",
39 help="不遞迴檢查子目錄"
40 )
41
42 args = parser.parse_args()
43
44 # 決定工作模式
45 if args.dir:
46 results = checker.check_directory(
47 args.dir,
48 recursive=not args.no_recursive
49 )
50 elif args.file_path:
51 results = [checker.check_file(args.file_path)]
52 else:
53 parser.print_help()
54 sys.exit(1)進階技巧
參數群組
1parser = argparse.ArgumentParser()
2
3# 必要參數群組
4required = parser.add_argument_group("required arguments")
5required.add_argument("--config", required=True)
6
7# 可選參數群組
8optional = parser.add_argument_group("optional arguments")
9optional.add_argument("--verbose", action="store_true")互斥參數
1group = parser.add_mutually_exclusive_group()
2group.add_argument("--json", action="store_true")
3group.add_argument("--yaml", action="store_true")
4# 只能選擇其中一個子命令
1parser = argparse.ArgumentParser()
2subparsers = parser.add_subparsers(dest="command")
3
4# add 子命令
5add_parser = subparsers.add_parser("add", help="新增項目")
6add_parser.add_argument("name")
7
8# list 子命令
9list_parser = subparsers.add_parser("list", help="列出項目")
10list_parser.add_argument("--all", action="store_true")
11
12args = parser.parse_args()
13if args.command == "add":
14 # 處理 add
15 pass
16elif args.command == "list":
17 # 處理 list
18 pass完整範例模板
1#!/usr/bin/env python3
2"""
3我的 CLI 工具
4
5使用方式:
6 python my_tool.py input.txt -o output.txt --verbose
7"""
8
9import argparse
10import sys
11
12
13def create_parser() -> argparse.ArgumentParser:
14 """建立參數解析器"""
15 parser = argparse.ArgumentParser(
16 description="我的 CLI 工具",
17 formatter_class=argparse.RawDescriptionHelpFormatter,
18 epilog="範例: python my_tool.py input.txt -o output.txt"
19 )
20
21 parser.add_argument(
22 "input",
23 help="輸入檔案"
24 )
25 parser.add_argument(
26 "-o", "--output",
27 default="output.txt",
28 help="輸出檔案 (預設: output.txt)"
29 )
30 parser.add_argument(
31 "-v", "--verbose",
32 action="store_true",
33 help="詳細輸出"
34 )
35 parser.add_argument(
36 "--version",
37 action="version",
38 version="%(prog)s 1.0.0"
39 )
40
41 return parser
42
43
44def main():
45 parser = create_parser()
46 args = parser.parse_args()
47
48 if args.verbose:
49 print(f"Input: {args.input}")
50 print(f"Output: {args.output}")
51
52 # 主要邏輯
53 process(args.input, args.output)
54
55
56if __name__ == "__main__":
57 main()最佳實踐
1. 提供有意義的 help 訊息
1parser.add_argument(
2 "--timeout",
3 type=int,
4 default=30,
5 help="超時時間(秒),預設 30" # 說明用途和預設值
6)2. 使用 epilog 提供使用範例
1parser = argparse.ArgumentParser(
2 epilog="""
3範例:
4 %(prog)s file.txt # 處理單一檔案
5 %(prog)s -d ./data --recursive # 遞迴處理目錄
6 """
7)3. 合理的 exit code
1if not results:
2 sys.exit(0) # 成功
3else:
4 sys.exit(1) # 失敗思考題
nargs="?"和nargs="*"有什麼區別?- 為什麼
--no-recursive使用action="store_true"而不是store_false? - 如何實作一個同時支援
--verbose和-v的參數?
實作練習
- 為現有的 Python 腳本添加 CLI 介面
- 實作一個支援子命令的 CLI 工具
- 建立一個參數驗證函式,檢查檔案是否存在
上一章:logging - 日誌系統 下一模組:物件導向設計