news 2026/3/13 19:25:07

Python 中的 click 框架

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python 中的 click 框架

一、什么是 Click 框架

Click 是 Python 生态中最流行的第三方 CLI 开发框架,由 Flask 作者 Armin Ronacher 开发,核心优势是:

  • 语法简洁(基于装饰器),比 Python 标准库argparse更易上手

  • 支持丰富的功能(子命令、参数验证、颜色输出、提示输入等)

  • 自动生成帮助文档,无需手动编写

  • 跨平台兼容(Windows/Linux/macOS)

二、安装 Click

通过 pip 安装:

pip install click

三、核心使用方法

1. 最简示例:基础命令

先写一个最简单的 CLI 程序,实现 “打招呼” 功能:

import click # @click.command() 把普通函数转为CLI命令 @click.command() def hello(): """这是一个简单的问候命令(帮助信息会自动生成)""" click.echo("Hello, Click!") # click.echo 替代print,兼容多平台 if __name__ == '__main__': hello()

运行效果:

2. 核心功能 1:选项(Option)

@click.option()用于定义可选参数(带---前缀),支持默认值、类型限制、帮助信息等:

import click @click.command() # 定义选项:--name / -n 是参数名,default是默认值,help是帮助信息 @click.option('--name', '-n', default='Guest', help='你的名字') # 定义布尔型选项:--uppercase / -u,is_flag=True 表示是开关(无需传值) @click.option('--uppercase', '-u', is_flag=True, help='是否转为大写') def greet(name, uppercase): """根据输入的名字打招呼""" message = f"Hello, {name}!" if uppercase: message = message.upper() click.echo(message) if __name__ == '__main__': greet()

运行效果

3. 核心功能 2:参数(Argument)

@click.argument()用于定义必选参数(无前缀,直接传值),适合必填的核心参数:

import click @click.command() # 必选参数:filename(无默认值,必须传) @click.argument('filename') # 可选选项:--mode / -m,限制可选值(type=click.Choice) @click.option('--mode', '-m', type=click.Choice(['read', 'write']), default='read', help='操作模式') def file_op(filename, mode): """对指定文件执行操作""" click.echo(f"操作文件:{filename},模式:{mode}") if __name__ == '__main__': file_op()

运行效果

4. 核心功能 3:子命令(Group)

@click.group()用于创建命令组,实现类似git addgit commit这样的子命令结构:

import click # 创建命令组 @click.group() def cli(): """一个包含多个子命令的CLI工具""" pass # 组本身无逻辑,仅用于承载子命令 # 子命令1:hello @cli.command() def hello(): """打招呼""" click.echo("Hello!") # 子命令2:bye @cli.command() @click.option('--name', default='Guest', help='你的名字') def bye(name): """说再见""" click.echo(f"Goodbye, {name}!") if __name__ == '__main__': cli()

运行效果

Click 的group(命令组)设计遵循 CLI 工具的通用范式(比如gitdocker),一次只能执行一个子命令

如果需要一次性执行多个子命令的逻辑,核心思路是:把每个子命令的业务逻辑抽离成普通函数,再新增一个 “批量执行” 的子命令,在里面调用这些普通函数

import click # ---------------------- # 第一步:抽离子命令的核心逻辑为普通函数 # ---------------------- def hello_logic(): """hello子命令的核心逻辑""" click.echo("执行hello逻辑:Hello!") def bye_logic(name="Guest"): """bye子命令的核心逻辑""" click.echo(f"执行bye逻辑:Goodbye, {name}!") # ---------------------- # 第二步:定义命令组和原有子命令(调用抽离的逻辑) # ---------------------- @click.group() def cli(): """支持批量执行多个子命令的CLI工具""" pass # 原有hello子命令(仅调用核心逻辑) @cli.command() def hello(): """单独执行hello""" hello_logic() # 原有bye子命令(仅调用核心逻辑) @cli.command() @click.option('--name', default='Guest', help='你的名字') def bye(name): """单独执行bye""" bye_logic(name) # ---------------------- # 第三步:新增批量执行的子命令 # ---------------------- @cli.command() @click.option('--cmds', '-c', multiple=True, type=click.Choice(['hello', 'bye']), required=True, help='要执行的子命令列表(可多选,比如 -c hello -c bye)') @click.option('--name', default='Guest', help='传给bye的名字参数') def batch(cmds, name): """动态选择批量执行的子命令""" click.echo(f"===== 开始批量执行:{cmds} =====") for cmd in cmds: if cmd == 'hello': hello_logic() elif cmd == 'bye': bye_logic(name) click.echo("===== 批量执行完成 =====") if __name__ == '__main__': cli()

运行效果:

4.1.子命令链式执行

chain=Trueclick.Group的关键参数,作用是允许在一次命令行调用中,按顺序执行多个子命令(即 “链式执行”)。

默认情况下(chain=False,默认值),命令组一次只能执行一个子命令(比如cli hellocli bye);开启chain=True后,可连续执行多个子命令(比如cli hello bye),框架会按输入顺序依次调用每个子命令。

下面是一个极简示例,直观展示chain=True的效果:

import click # 开启链式执行的命令组 @click.group(chain=True) def cli(): """支持链式执行多个子命令的CLI工具""" pass # 子命令1:打招呼 @cli.command() @click.option('--name', default='Guest', help='你的名字') def hello(name): """执行打招呼逻辑""" click.echo(f"[第一步] Hello, {name}!") # 子命令2:说再见 @cli.command() def bye(): """执行说再见逻辑""" click.echo(f"[第二步] Goodbye!") # 子命令3:输出时间 @cli.command() def show_time(): """输出当前时间""" from datetime import datetime now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") click.echo(f"[第三步] 当前时间:{now}") if __name__ == '__main__': cli()

运行效果:

# 链式执行3个子命令
python chain_demo.py hello --name 小明 bye show_time

输出结果(严格按输入顺序执行):

[第一步] Hello, 小明! [第二步] Goodbye! [第三步] 当前时间:2026-02-03 15:30:00

若需要让后续子命令接收前一个子命令的结果,可通过click.pass_context结合上下文的obj属性实现:

import click @click.group(chain=True) @click.pass_context # 传递上下文对象 def cli(ctx): # 初始化上下文存储容器,用于子命令间传值 ctx.ensure_object(dict) ctx.obj['history'] = [] # 存储每个子命令的执行结果 @cli.command() @click.pass_context @click.option('--name', default='Guest') def hello(ctx, name): msg = f"Hello, {name}!" click.echo(msg) ctx.obj['history'].append(msg) # 存入上下文 return msg @cli.command() @click.pass_context def bye(ctx): msg = "Goodbye!" click.echo(msg) ctx.obj['history'].append(msg) # 读取前一个子命令的结果 if len(ctx.obj['history']) >= 2: click.echo(f"← 前一个命令的结果:{ctx.obj['history'][-2]}") if __name__ == '__main__': cli()

运行效果:

python chain_demo.py hello --name 小明 bye

输出:

Hello, 小明! Goodbye! ← 前一个命令的结果:Hello, 小明!

默认情况下,即使某个子命令执行失败,后续子命令仍会执行;如需中断链式执行,可在子命令中主动抛出click.Abort()异常:

@cli.command() def error_demo(): click.echo("这个命令会触发中断!") raise click.Abort() # 中断后续所有子命令

四、实用进阶特性

  1. 提示输入:当用户未传参数时,自动提示输入

    @click.command() @click.option('--name', prompt='请输入你的名字', help='你的名字') def ask_name(name): click.echo(f"你输入的名字是:{name}")
  2. 密码输入:隐藏输入的敏感信息

    @click.command() @click.option('--password', prompt=True, hide_input=True, confirmation_prompt=True) def input_pwd(password): click.echo("密码已输入(已隐藏)")
  3. 颜色输出:让 CLI 输出更美观(需安装 colorama 兼容 Windows)

    pip install colorama
    @click.command() def color_text(): click.echo(click.style("成功", fg="green")) # 绿色文字 click.echo(click.style("警告", fg="yellow", bg="black")) # 黄字黑底 click.echo(click.style("错误", fg="red", bold=True)) # 红色加粗
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/12 16:47:17

五大热门远程控制软件全方位测评,2026年远控王者花落谁家?

一、核心性能对比:画质与流畅度的较量当一款软件或设备真正进入使用场景后,参数表上的数字往往就失去了存在感。用户最直观、也最难妥协的体验,始终只有两点——画面是否清晰,操作是否顺畅。画质与流畅度决定了用户操作是否顺畅&a…

作者头像 李华
网站建设 2026/3/13 17:24:24

专业级模型 GLM-OCR

智谱宣布正式发布并开源一款轻量的专业级 OCR 模型 GLM-OCR,主打“小尺寸、高精度”。其核心亮点如下性能SOTA:以94.6分登顶OmniDocBench V1.5,并在公式识别、表格识别、信息抽取的多项主流基准中均取得SOTA表现;场景优化&#xf…

作者头像 李华
网站建设 2026/3/13 8:33:00

【TS】TS总结

1. 类型声明 通过 :类型 明确指定变量的类型。示例:let a: string; let b: number; let c: boolean; function demo(x: number, y: number): number { return x y; }2. 类型推断 TypeScript 会根据赋值自动推断变量类型。示例:let d -99; // 推断为 …

作者头像 李华
网站建设 2026/3/13 1:34:51

【Java SE 基础学习打卡】37 二维数组

目录前言一、二维数组概述:数组的数组,存表格型数据的利器1.1 生活化类比1.2 编程定义1.3 直观结构(以 3 行 2 列的成绩表为例)二、二维数组的定义与初始化:造好表格式收纳盒2.1 定义格式(2 种,…

作者头像 李华
网站建设 2026/3/9 16:45:21

Java与AI融合新探索:JBoltAI框架能力深度剖析

html在人工智能技术日新月异的背景下,Java作为企业级应用开发的主力军,如何有效融合AI技术成为行业关注的焦点。JBoltAI框架以其独特的AIGS能力、数据管理与处理能力、数据可视化能力,为Java开发者铺就了一条通往AI世界的坚实道路。本文将基于…

作者头像 李华
网站建设 2026/3/11 19:50:06

豆包和InfiniSynapse 联网搜索哪家强:一起寻找元气

今天我无意在群里看到如下一段对话:发这个截图的朋友其实是想展示,其实豆包完全可以替代搜索,而且还没广告。但是如果搜索结果返回的不太好,比如信息有冲突之类的,其实大家应该能够感受到,像豆包/DeepSeek …

作者头像 李华