Python 命令行参数解析教程

1. 基础入门:sys.argv 快速获取

如果你只想拿到用户敲进去的原始字符串sys.argv 是最快的方式。它是一个列表,第一个元素永远是脚本自身的名称(如 script.py),后面依次跟着所有空格分隔的输入。

import sys

print("接收到的完整命令行参数列表:", sys.argv)

将上面的代码保存为 basic_argv.py,在终端里运行:

python basic_argv.py hello world 123

输出将是:

接收到的完整命令行参数列表: ['basic_argv.py', 'hello', 'world', '123']

这种方法虽然直接,但缺点也很明显:没有类型检查、没有约束逻辑、没有帮助文档——工具稍微复杂一点,你自己和你的用户都会崩溃。


2. 核心工具:argparse 标准库

只要你的命令行工具需要正式一点的用户体验,Python 自带的 argparse 就是首选。它不需要额外安装,能自动生成 -h/--help 帮助文档,并且覆盖了绝大多数命令行场景。

2.1 三步搭建框架

使用 argparse 的流程非常简单,只要三步:

  1. 创建一个 ArgumentParser 对象(相当于一个“参数收纳箱”)
  2. 通过 add_argument() 往箱子里添加各种参数规则
  3. 调用 parse_args() 解析参数,得到一个属性化对象
import argparse

# 第一步:搭建收纳箱
parser = argparse.ArgumentParser(
    prog="my_cli_tool",       # 工具的正式名称(帮助文档中显示)
    description="这是一个示例工具的简介",
    epilog="© 2024 我的开发笔记"  # 帮助文档结尾的附注
)

# 第二步:添加参数
parser.add_argument("file_path", help="要操作的文件路径")

# 第三步:解析并使用
if __name__ == "__main__":
    args = parser.parse_args()
    print(f"开始处理文件:{args.file_path}")

就这么简单!运行 python my_cli_tool.py -h,你会立刻看到一份结构清晰的帮助信息。

2.2 五种常用的参数类型

① 位置参数(必填,没有短/长选项)

位置参数按用户输入的顺序绑定,适合逻辑上必须先填的核心内容,例如文件路径、操作名。

parser.add_argument(
    "outfile",
    help="数据库备份的输出文件路径"  # 一定要写 help!
)

② 可选参数(带有短/长选项)

可选参数可以以任意顺序给出,适合开关、配置项等非核心内容。短选项一般是单字母(如 -u),长选项更易读(如 --user)。

parser.add_argument(
    "-u", "--user",    # 可以单独写 -u 或 --user,也可以同时写
    required=True,     # 可选参数也能变成必填
    help="登录数据库的用户名"
)

③ 带默认值的可选参数

给可选参数设置默认值能减轻用户的负担,默认值会在帮助文档的 (default: xxx) 里自动展示。

parser.add_argument(
    "--host",
    default="localhost",
    help="MySQL 主机地址"
)

④ 类型转换与验证

默认情况下,所有参数都被当作字符串。通过 type 可以自动转换成 intfloat 等类型,甚至自定义验证函数。

# 直接转换整数
parser.add_argument(
    "--port",
    type=int,
    default=3306,
    help="MySQL 端口号"
)

# 自定义验证:限制端口范围
def check_port(port_str):
    port = int(port_str)
    if 1 <= port <= 65535:
        return port
    raise argparse.ArgumentTypeError(f"端口必须在 1-65535 之间,你输入的是 {port}")

parser.add_argument(
    "--safe-port",
    type=check_port,
    default=3306,
    help="安全的 MySQL 端口号"
)

提示:自定义验证函数会在用户输入非法值时马上抛出清晰的错误,比解析后再检查体验好得多。

⑤ 布尔开关参数

这种参数不需要后面跟值,只要出现在命令行里,就自动设为 True(或者 False)。通过 action 参数控制。

# 只要写 -g 就设为 True
parser.add_argument(
    "-g", "--gz",
    action="store_true",
    help="是否启用 GZIP 压缩备份文件"
)

# 写 --no-color 就设为 False(默认是 True)
parser.add_argument(
    "--no-color",
    action="store_false",
    dest="enable_color",  # 修改解析后对象的属性名
    default=True,
    help="是否禁用彩色输出"
)

⑥ 限定选择的参数

使用 choices 限定输入只能是指定列表中的某个值,帮助文档也会自动列出这些选项。

parser.add_argument(
    "--format",
    choices=["json", "xml", "csv"],
    default="json",
    help="备份文件的输出格式"
)

2.3 完整的实战示例:数据库备份工具

把上面的知识点整合起来,写一个虽然简单但五脏俱全的 MySQL 备份工具模板。

import argparse

def backup_database(outfile, host, port, user, password, database, gz):
    """模拟数据库备份的核心逻辑"""
    print(f"✅ 开始准备备份任务")
    print(f"📁 输出文件:{outfile}{'.gz' if gz else ''}")
    print(f"🔗 连接信息:{user}@{host}:{port}/{database}")
    if gz:
        print("📦 GZIP 压缩已启用")

if __name__ == "__main__":
    # 1. 搭收纳箱
    parser = argparse.ArgumentParser(
        prog="db_backup",
        description="轻量级 MySQL 数据库本地备份工具",
        epilog="⚠️ 使用前请确保已安装 mysqldump"
    )

    # 2. 添加所有参数
    parser.add_argument("outfile", help="备份文件的本地路径(不带.gz后缀)")
    parser.add_argument("--host", default="localhost", help="MySQL 主机地址")

    def check_port(port_str):
        port = int(port_str)
        if 1 <= port <= 65535:
            return port
        raise argparse.ArgumentTypeError(f"端口必须在 1-65535 之间")
    parser.add_argument("--port", type=check_port, default=3306, help="MySQL 端口号")

    parser.add_argument("-u", "--user", required=True, help="登录用户名")
    parser.add_argument("-p", "--password", required=True, help="登录密码")
    parser.add_argument("--database", required=True, help="要备份的数据库名")
    parser.add_argument("-g", "--gz", action="store_true", help="启用 GZIP 压缩")

    # 3. 解析并运行
    args = parser.parse_args()
    backup_database(
        args.outfile,
        args.host,
        args.port,
        args.user,
        args.password,
        args.database,
        args.gz
    )

现在运行 python db_backup.py -h 看一眼自动生成的帮助文档,你会感到真正的省心——再也不用自己手写一堆说明文字了。


2.4 进阶:分组 + 子命令

当参数数量超过 10 个,或者一个工具内有多个独立功能(比如“备份”和“恢复”),就可以用分组子命令来让用户的输入更有条理。

参数分组

将相关参数归到同一个标题下,帮助文档立马变得清晰:

# 分组1:连接配置
conn_group = parser.add_argument_group("连接配置", "关于 MySQL 服务器的设置")
conn_group.add_argument("--host", default="localhost")
conn_group.add_argument("--port", type=int, default=3306)
conn_group.add_argument("-u", "--user", required=True)
conn_group.add_argument("-p", "--password", required=True)

# 分组2:备份配置
backup_group = parser.add_argument_group("备份配置", "关于备份文件的设置")
backup_group.add_argument("outfile")
backup_group.add_argument("--format", choices=["sql", "csv"], default="sql")
backup_group.add_argument("-g", "--gz", action="store_true")

子命令

子命令相当于把一个大型工具拆成若干个独立的小命令,就像 git addgit commit 那样。使用 subparsers 可以轻松实现。

import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser(prog="db_tool", description="MySQL 管理工具集")
    # 必须设置 dest,这样才能知道用户选择了哪个子命令
    subparsers = parser.add_subparsers(dest="command", required=True, help="可用的子命令")

    # 子命令1:backup
    backup_parser = subparsers.add_parser("backup", help="备份数据库到本地")
    backup_parser.add_argument("outfile", help="输出文件路径")
    # 这里可以继续添加 --host、--user 等参数...

    # 子命令2:restore
    restore_parser = subparsers.add_parser("restore", help="从本地文件恢复数据库")
    restore_parser.add_argument("infile", help="输入的备份文件路径")
    # ...

    args = parser.parse_args()
    if args.command == "backup":
        print("执行备份逻辑")
    elif args.command == "restore":
        print("执行恢复逻辑")

3. 现代替代方案(需要安装)

虽然 argparse 已经足够强大,但如果你追求更简洁的语法或者更现代的交互体验,可以了解一下下面这两个第三方库。

3.1 Click

Click 使用装饰器来定义命令,语法非常优雅。它还贴心地提供了密码隐藏等功能。

import click

@click.command()
@click.argument("outfile")
@click.option("--host", default="localhost", help="MySQL 主机")
@click.option("--port", default=3306, type=int, help="MySQL 端口")
@click.option("-u", "--user", required=True, help="用户名")
@click.password_option("-p", "--password", help="密码")  # 输入时不回显
@click.option("-g", "--gz", is_flag=True, help="启用压缩")
def db_backup(outfile, host, port, user, password, gz):
    click.echo(f"备份到 {outfile}")

if __name__ == "__main__":
    db_backup()

安装:pip install click

3.2 Typer(基于 Click)

Typer 完全拥抱 Python 类型提示,代码的可读性和维护性直接拉满,还支持自动补全。

import typer

app = typer.Typer()

@app.command()
def backup(
    outfile: str,
    host: str = "localhost",
    port: int = 3306,
    user: str = typer.Option(..., help="用户名"),      # ... 表示必填
    password: str = typer.Option(..., prompt=True, hide_input=True, help="密码"),
    gz: bool = typer.Option(False, "--gz", "-g", help="启用压缩")
):
    typer.echo(f"✅ 备份到 {outfile}")

if __name__ == "__main__":
    app()

安装:pip install typer


4. 最佳实践总结

  1. 一定要写 help:这是对用户(以及未来的你自己)最基本的尊重
  2. 设置合理的默认值:例如端口默认 3306、格式默认 json
  3. 参数命名要直观:长选项尽量用完整单词,短选项选有意义的单字母
  4. 尽早验证输入:利用 type 自定义验证函数,比解析完再检查友好得多
  5. 复杂工具使用子命令:避免所有参数堆在一起

5. 快速决策表

场景推荐工具
临时脚本,只有一两个参数sys.argv
正式工具,不想引入额外依赖argparse
喜欢装饰器语法,需要密码隐藏Click
痴迷类型提示,想要交互式补全Typer

无论你的项目最终选择哪一个,argparse 都是每个 Python 开发者必须扎实掌握的基础,在此基础上,再根据具体需求挑选更现代的替代品就好。