简介
Click
是 Python 中用于构建命令行界面的强大库,设计目标是:用尽可能少的代码,构建可组合的命令行界面
入门
import click
@click.command()
@click.option('--count', default=1, help='重复次数')
@click.argument('name')
def hello(count, name):
for _ in range(count):
click.echo(f"Hello, {name}!")
if __name__ == '__main__':
hello()
运行
$ python app.py --count=3 Alice
Hello, Alice!
Hello, Alice!
Hello, Alice!
核心组件
注册命令
@click.command()
位置参数
@click.argument('filename')
调用时必须写
$ python app.py myfile.txt
可选参数
@click.option('--debug', is_flag=True, help='开启调试模式')
@click.option('--level', type=int, default=3)
输出函数
click.echo()
类型系统
@click.argument('path', type=click.Path(exists=True))
创建命令组
@click.group()
def cli():
pass
@cli.command()
def init():
click.echo("初始化")
@cli.command()
def start():
click.echo("启动")
if __name__ == '__main__':
cli()
执行
$ python app.py init
初始化
提示
@click.option('--username', prompt='用户名')
@click.option('--password', prompt=True, hide_input=True)
回调函数
在参数解析后执行特定函数
def validate(ctx, param, value):
if value < 0:
raise click.BadParameter('必须为非负数')
return value
@click.option('--num', callback=validate, type=int)
命令别名
@click.command(name='run', help='执行')
自定义帮助输出
@click.group(context_settings=dict(help_option_names=['-h', '--help']))
实用场景
多值选项
@click.option('--path', multiple=True)
调用
$ python app.py --path a --path b
布尔值选项
@click.option('--verbose/--no-verbose', default=True)
环境变量选项
@click.option('--config', envvar='APP_CONFIG')
实战项目结构
下面是一个实战级的 Python CLI 工具项目示例,基于 Click 实现,模拟一个日常常见的命令行工具
项目目标
我们创建一个名为 tasker
的命令行工具,用来:
- 管理待办事项(任务列表)
- 支持子命令:
add
,list
,done
,remove
- 本地保存任务(使用 JSON 文件作为数据库)
- 可选支持
--verbose
模式
项目结构
tasker/
├── __main__.py # 入口点
├── cli.py # 命令组定义
├── commands/
│ ├── add.py # 添加任务
│ ├── list.py # 列出任务
│ ├── done.py # 标记完成
│ └── remove.py # 删除任务
├── storage.py # JSON 文件存储逻辑
├── model.py # 任务数据结构
├── config.py # 配置管理(如路径)
└── task_db.json # 数据文件(运行时自动生成)
安装入口(可选)
在 pyproject.toml
或 setup.py
中添加:
[project.scripts]
tasker = "tasker.__main__:cli"
代码示例
__main__.py
from tasker.cli import cli
if __name__ == "__main__":
cli()
cli.py
import click
from tasker.commands import add, list, done, remove
@click.group()
@click.option('--verbose', is_flag=True, help="显示详细信息")
@click.pass_context
def cli(ctx, verbose):
ctx.ensure_object(dict)
ctx.obj['verbose'] = verbose
cli.add_command(add.command)
cli.add_command(list.command)
cli.add_command(done.command)
cli.add_command(remove.command)
commands/add.py
import click
from tasker.storage import load_tasks, save_tasks
@click.command()
@click.argument('title')
@click.pass_context
def command(ctx, title):
tasks = load_tasks()
tasks.append({'title': title, 'done': False})
save_tasks(tasks)
click.echo(f"✅ 添加任务: {title}")
commands/list.py
import click
from tasker.storage import load_tasks
@click.command()
@click.pass_context
def command(ctx):
tasks = load_tasks()
for i, task in enumerate(tasks, 1):
status = "✔" if task['done'] else "✘"
click.echo(f"{i}. [{status}] {task['title']}")
commands/done.py
import click
from tasker.storage import load_tasks, save_tasks
@click.command()
@click.argument('index', type=int)
@click.pass_context
def command(ctx, index):
tasks = load_tasks()
if 0 < index <= len(tasks):
tasks[index - 1]['done'] = True
save_tasks(tasks)
click.echo(f"🎉 任务完成: {tasks[index - 1]['title']}")
else:
click.echo("❌ 无效的任务编号")
commands/remove.py
import click
from tasker.storage import load_tasks, save_tasks
@click.command()
@click.argument('index', type=int)
@click.pass_context
def command(ctx, index):
tasks = load_tasks()
if 0 < index <= len(tasks):
removed = tasks.pop(index - 1)
save_tasks(tasks)
click.echo(f"🗑 删除任务: {removed['title']}")
else:
click.echo("❌ 无效的任务编号")
storage.py
import os
import json
DB_PATH = os.path.expanduser("~/.tasker_db.json")
def load_tasks():
if not os.path.exists(DB_PATH):
return []
with open(DB_PATH, "r") as f:
return json.load(f)
def save_tasks(tasks):
with open(DB_PATH, "w") as f:
json.dump(tasks, f, indent=2)
示例运行效果
$ tasker add "写 Click 教程"
✅ 添加任务: 写 Click 教程
$ tasker list
1. [✘] 写 Click 教程
$ tasker done 1
🎉 任务完成: 写 Click 教程
$ tasker list
1. [✔] 写 Click 教程
$ tasker remove 1
🗑 删除任务: 写 Click 教程