Python argparse:在 10 分钟内构建 CLI 工具

发布: (2026年5月10日 GMT+8 07:20)
9 分钟阅读
原文: Dev.to

Source: Dev.to

🎁 免费: AI 出版清单 — 用 Python 的 7 步
完整流程:(随意付费,最低 $9.99)

问题

你写了一个快速脚本,硬编码了文件名,随后立刻需要更改它。于是你去使用 sys.argv

import sys

filename = sys.argv[1]
count = int(sys.argv[2])

它能工作……直到它不工作为止:

  • 不带参数运行 → IndexError
  • 在需要整数的地方传入非整数 → 崩溃。
  • 没有帮助文本,没有验证,没有默认值。
  • 其他人要使用你的脚本时必须阅读源码才能知道如何运行。

为什么 argparse

argparse(标准库)解决了所有这些问题。
一次调用 parse_args() 就能处理:

  • 读取 sys.argv
  • 验证输入
  • 打印帮助信息(--help

基本模板

import argparse

parser = argparse.ArgumentParser(
    description="My CLI tool — does useful things."
)
args = parser.parse_args()

位置参数

必需的,并通过位置而非名称来标识:

parser.add_argument("filename", help="Path to the input file")
parser.add_argument("count", help="Number of items to process")

可选(标志)参数

使用 -- 前缀;短别名是可选的:

parser.add_argument(
    "--output", "-o",
    help="Output file path",
    default="output.txt"
)
parser.add_argument(
    "--verbose", "-v",
    help="Enable verbose logging",
    action="store_true"
)

类型转换与可选项

argparse 完成转换和验证:

parser.add_argument(
    "--count", type=int, default=10,
    help="Number of items"
)
parser.add_argument(
    "--rate", type=float, default=1.5,
    help="Processing rate"
)
parser.add_argument(
    "--format",
    choices=["json", "csv", "txt"],
    default="json",
    help="Output format"
)

如果用户运行 --count helloargparse 会打印简洁的错误信息并退出——不会出现堆栈跟踪。

nargs 和列表

示例含义
parser.add_argument("--title", required=True, help="Article title (required)")必需的可选参数
parser.add_argument("--tags", nargs="+", help="One or more tags")一个 或多个 值 (+)
parser.add_argument("--tags", nargs="*", help="Zero or more tags")零个 或多个 值 (*)

结果是一个 Python 列表,你可以直接迭代:

args = parser.parse_args()
for tag in args.tags:
    print(tag)

布尔标志 (store_true / store_false)

parser.add_argument(
    "--dry-run",
    action="store_true",
    help="Simulate without writing"
)
parser.add_argument(
    "--no-color",
    action="store_false",
    dest="color",
    help="Disable color output"
)

用法

python publish.py --dry-run   # args.dry_run 为 True
python publish.py             # args.dry_run 为 False
python publish.py --no-color # args.color 为 False

子命令(如 gitdockerpip

parser = argparse.ArgumentParser(description="Publish queue manager")
subparsers = parser.add_subparsers(dest="command", required=True)

# `publish` subcommand
publish_parser = subparsers.add_parser(
    "publish",
    help="Publish the next article in queue"
)
publish_parser.add_argument(
    "--dry-run",
    action="store_true",
    help="Simulate without publishing"
)

# `list` subcommand
list_parser = subparsers.add_parser(
    "list",
    help="Show the publish queue"
)
list_parser.add_argument(
    "--format",
    choices=["table", "json"],
    default="table"
)

args.command 告诉你选择了哪个子命令,每个子命令都有自己的参数。

--verbose / -v 模式

一种常见的做法是使用 --verbose 在运行时设置日志级别:

import argparse
import logging

parser = argparse.ArgumentParser()
parser.add_argument(
    "--verbose", "-v",
    action="store_true",
    help="Enable debug logging"
)
args = parser.parse_args()

logging.basicConfig(
    level=logging.DEBUG if args.verbose else logging.INFO,
    format="%(levelname)s: %(message)s"
)

log = logging.getLogger(__name__)
log.info("Starting...")
log.debug("This only shows with --verbose")

完整示例:文章发布队列 CLI

#!/usr/bin/env python3
"""
publish_queue.py — CLI for managing the article publish queue.
Usage: python publish_queue.py  [options]
"""

import argparse
import json
import logging
import sys
from pathlib import Path

QUEUE_FILE = Path("queue.json")

def load_queue() -> list[dict]:
    """Load the queue from JSON; return empty list if file missing."""
    if not QUEUE_FILE.exists():
        return []
    return json.loads(QUEUE_FILE.read_text())

def save_queue(queue: list[dict]) -> None:
    """Write the queue back to disk."""
    QUEUE_FILE.write_text(json.dumps(queue, indent=2))

def cmd_list(args: argparse.Namespace) -> None:
    queue = load_queue()
    if not queue:
        print("Queue is empty.")
        return
    for i, article in enumerate(queue, 1):
        status = "[published]" if article.get("published") else "[pending]  "
        tags = ", ".join(article.get("tags", []))
        print(f"{i}. {status} {article['title']} ({tags})")

def cmd_add(args: argparse.Namespace) -> None:
    queue = load_queue()
    article = {
        "title": args.title,
        "tags": args.tags or [],
        "published": False,
    }
    queue.append(article)
    save_queue(queue)
    logging.info("Added: %s", args.title)
    print(f"Added '{args.title}' to queue. Total: {len(queue)} articles.")

def cmd_publish(args: argparse.Namespace) -> None:
    queue = load_queue()
    pending = [a for a in queue if not a.get("published")]
    if not pending:
        print("No pending articles.")
        return
    next_article = pending[0]
    if args.dry_run:
        print(f"[DRY RUN] Would publish: {next_article['title']}")
        return
    next_article["published"] = True
    save_queue(queue)
    print(f"Published: {next_article['title']}")
    logging.info("Published: %s", next_article["title"])

def main() -> None:
    parser = argparse.ArgumentParser(
        description="Publish queue manager"
    )
    subparsers = parser.add_subparsers(dest="command", required=True)

    # add subcommand
    add_parser = subparsers.add_parser(
        "add",
        help="Add a new article to the queue"
    )
    add_parser.add_argument(
        "--title",
        required=True,
        help="Article title (required)"
    )
    add_parser.add_argument(
        "--tags",
        nargs="*",
        help="Zero or more tags"
    )
    add_parser.set_defaults(func=cmd_add)

    # list subcommand
    list_parser = subparsers.add_parser(
        "list",
        help="Show the publish queue"
    )
    list_parser.set_defaults(func=cmd_list)

    # publish subcommand
    publish_parser = subparsers.add_parser(
        "publish",
        help="Publish the next pending article"
    )
    publish_parser.add_argument(
        "--dry-run",
        action="store_true",
        help="Simulate without publishing"
    )
    publish_parser.set_defaults(func=cmd_publish)

    # global verbose flag
    parser.add_argument(
        "--verbose", "-v",
        action="store_true",
        help="Enable debug logging"
    )

    args = parser.parse_args()

    # configure logging *after* parsing arguments
    logging.basicConfig(
        level=logging.DEBUG if args.verbose else logging.INFO,
        format="%(levelname)s: %(message)s"
    )

    # dispatch to the chosen subcommand
    args.func(args)

if __name__ == "__main__":
    main()

运行脚本:

python publish_queue.py add --title "My First Article" --tags python tutorial
python publish_queue.py list
python publish_queue.py publish --dry-run
python publish_queue.py publish -v

TL;DR

  • argparse 将单行脚本转换为完善的 CLI。
  • 定义 positional(位置)和 optional(可选)参数,使用 type conversion(类型转换)、choices(可选值)和 nargs(参数数量)来处理列表。
  • 使用 store_true / store_false 来实现标志位。
  • 利用 sub‑parsers 实现类似 git 的子命令。
  • 添加 --verbose 标志以切换日志输出。

试一试——你的脚本将在几分钟内变得更健壮、自动生成文档且更友好!

publish_queue.py – 基于 Argument‑Parser 的 CLI

import argparse
import logging

# Example logging call used by the script
logging.info("Published: %s", next_article["title"])

def build_parser() -> argparse.ArgumentParser:
    """Create the top‑level argument parser."""
    parser = argparse.ArgumentParser(
        prog="publish_queue",
        description="Manage your article publish queue.",
    )
    parser.add_argument(
        "--verbose", "-v",
        action="store_true",
        help="Enable debug logging",
    )

    subparsers = parser.add_subparsers(dest="command", required=True)

    # ── list ────────────────────────────────────────────────────────
    list_parser = subparsers.add_parser("list", help="Show the publish queue")
    list_parser.set_defaults(func=cmd_list)

    # ── add ────────────────────────────────────────────────────────
    add_parser = subparsers.add_parser("add", help="Add an article to the queue")
    add_parser.add_argument("--title", required=True, help="Article title")
    add_parser.add_argument("--tags", nargs="*", help="Tags for the article")
    add_parser.set_defaults(func=cmd_add)

    # ── publish ─────────────────────────────────────────────────────
    publish_parser = subparsers.add_parser(
        "publish", help="Publish the next pending article"
    )
    publish_parser.add_argument(
        "--dry-run", action="store_true", help="Simulate without writing"
    )
    publish_parser.set_defaults(func=cmd_publish)

    return parser

def main() -> None:
    """Entry point for the CLI."""
    parser = build_parser()
    args = parser.parse_args()

    logging.basicConfig(
        level=logging.DEBUG if args.verbose else logging.INFO,
        format="%(levelname)s: %(message)s",
    )

    # Dispatch to the appropriate sub‑command function
    args.func(args)

if __name__ == "__main__":
    main()

--help 输出

$ python publish_queue.py --help
usage: publish_queue [-h] [--verbose] {list,add,publish} ...

Manage your article publish queue.

positional arguments:
  {list,add,publish}
    list              Show the publish queue
    add               Add an article to the queue
    publish           Publish the next pending article

options:
  -h, --help          show this help message and exit
  --verbose, -v       Enable debug logging
$ python publish_queue.py add --help
usage: publish_queue add [-h] --title TITLE [--tags [TAGS ...]]

options:
  -h, --help           show this help message and exit
  --title TITLE        Article title
  --tags [TAGS ...]    Tags for the article

示例工作流

# Add articles to the queue
python publish_queue.py add --title "Python argparse guide" \
    --tags python beginners tutorial
python publish_queue.py add --title "Automate your workflow" \
    --tags python automation

# List the queue
python publish_queue.py list
# 1. [pending]   Python argparse guide (python, beginners, tutorial)
# 2. [pending]   Automate your workflow (python, automation)

# Publish the next article (dry‑run first)
python publish_queue.py publish --dry-run
# [DRY RUN] Would publish: Python argparse guide

python publish_queue.py publish
# Published: Python argparse guide

# Check the updated queue with debug logging
python publish_queue.py list --verbose

Argparse 模式速查表

模式何时使用
type=int / type=float任意数值输入
choices=[...]固定的一组有效值
required=True必需的可选参数
nargs="+" / nargs="*"值的列表
action="store_true"布尔标志
add_subparsers()多命令工具
set_defaults(func=…)分派到子命令函数

argparse 自动提供的功能

  • -h/--help – 从 help= 字符串生成
  • 类型验证 – 清晰的错误信息,无回溯
  • 默认值 – 在帮助输出中记录
  • 使用行 – 根据参数定义自动生成

不需要第三方库。 一切都使用 Python 标准库即可工作。

进一步阅读与资源

  • 完整流水线中的 publish‑queue CLIgermy5.gumroad.com/l/xhxkzz(随意付费,最低 $9.99)
  • 您的第一个自动化 Python 脚本:验证并自行运行
  • Python 日志:停止在自动化脚本中使用 print()
  • 如何使用 Cron 调度 Python 脚本:初学者完整指南
0 浏览
Back to Blog

相关文章

阅读更多 »

Show HN:TikTok 但用于学术论文

功能 发现 一个了解你正在研究内容的 feed 根据你的兴趣、热门话题、新鲜度和社区参与度对 papers 进行排名。 选择一个 fe…