具体使用
1. 安装
pip install questionary
2. 基本输入 (Text Input)
import questionary
name = questionary.text("请输入您的名字:").ask()
print(f"你好, {name}!")
- 功能:获取用户输入的文本。
- 常用参数:
message
(提示信息)、default
(默认值)、validate
(输入验证)。
3. 单选列表 (Select)
choice = questionary.select(
"请选择您喜欢的编程语言:",
choices=["Python", "JavaScript", "Java", "C++"]
).ask()
print(f"您选择了: {choice}")
- 功能:从列表中选择一个选项。
- 常用参数:
choices
(选项列表)、qmark
(问题标记符号)。
4. 多选列表 (Checkbox)
choices = questionary.checkbox(
"选择您使用的操作系统:",
choices=["Windows", "macOS", "Linux"]
).ask()
print(f"您选择了: {', '.join(choices)}")
- 功能:允许用户选择多个选项。
- 注意:返回一个列表。
5. 确认对话框 (Confirm)
confirmed = questionary.confirm("确定要删除文件吗?").ask()
if confirmed:
print("文件已删除")
else:
print("操作已取消")
- 功能:返回
True
或False
。
6. 密码输入 (Password)
password = questionary.password("请输入密码:").ask()
print(f"密码已接收")
- 功能:隐藏用户输入内容(显示为星号)。
7. 自动补全输入 (Autocomplete)
language = questionary.autocomplete(
"输入编程语言:",
choices=["Python", "PHP", "Perl", "JavaScript"],
).ask()
print(f"搜索语言: {language}")
- 功能:输入时自动匹配选项。
- 注意:用户也可以输入未列出的内容。
8. 链式调用 (Chained Questions)
questions = [
{"type": "text", "name": "name", "message": "您的名字?"},
{"type": "confirm", "name": "confirm", "message": "确认信息?"}
]
answers = questionary.prompt(questions)
print(answers)
- 功能:通过字典列表定义多个连续问题。
9. 输入验证 (Validation)
def validate_age(age):
if not age.isdigit():
return "请输入数字"
if int(age) < 18:
return "年龄必须大于18岁"
return True
age = questionary.text(
"请输入您的年龄:",
validate=validate_age
).ask()
print(f"年龄: {age}")
- 功能:自定义验证函数确保输入合法。
10. 异步支持 (Async)
import asyncio
async def main():
name = await questionary.text("您的名字?").async_ask()
print(f"Hello, {name}")
asyncio.run(main())
- 功能:在异步代码中使用
async_ask()
。
中级应用
1. 动态问题生成(根据前置答案调整后续问题)
import questionary
# 第一步:选择用户角色
role = questionary.select(
"选择您的角色:",
choices=["开发者", "测试工程师", "运维人员"]
).ask() # :ml-citation{ref="2" data="citationList"}
# 第二步:动态生成问题
if role == "开发者":
lang = questionary.checkbox(
"您使用的编程语言:",
choices=["Python", "Java", "Go"]
).ask()
elif role == "运维人员":
tool = questionary.confirm("是否使用 Kubernetes?").ask()
- 解析:通过前置问题结果动态调整后续问题类型
- 应用场景:多步骤表单、个性化配置工具
2. 自定义交互样式
questionary.text(
"请输入项目名称:",
qmark="⚡", # 修改问题前缀符号
style=questionary.Style([
('qmark', 'fg:#FFA500 bold'), # 橙色加粗
('answer', 'fg:#008000 italic') # 绿色斜体
])
).ask()
- 解析:通过
qmark
修改问题标记,style
参数自定义颜色和字体样式 - 扩展能力:支持 ANSI 颜色代码和样式组合
3. 文件路径选择与验证
def validate_path(path):
if not path.endswith(".json"):
return "必须为 JSON 文件"
return True
file_path = questionary.path(
"请输入配置文件路径:",
default="config.json",
validate=validate_path,
only_files=True # 仅允许选择文件
).ask()
- 解析:
path
类型专用于文件/目录选择,only_files
限制仅选择文件 - 典型用途:CLI 工具配置文件管理
4. 分页式复杂表单
questions = [
{"type": "text", "name": "name", "message": "姓名"},
{"type": "password", "name": "pwd", "message": "密码"},
{"type": "confirm", "name": "agree", "message": "接受协议?"}
]
answers = questionary.prompt(questions)
print(f"注册用户: {answers['name']}")
- 解析:通过字典列表定义多步骤问题,自动按顺序执行
- 优势:代码结构清晰,便于维护复杂交互流程
5. 与 Rich 库结合实现彩色输出
from rich import print
import questionary
name = questionary.text("输入用户名:").ask()
print(f"[bold green]✔ 用户 {name} 登录成功[/bold green]")
- 解析:
questionary
负责输入交互,rich
增强输出可视化效果 - 组合价值:构建专业级命令行工具界面
6. 高级输入验证(正则表达式)
import re
questionary.text(
"请输入邮箱地址:",
validate=lambda x: re.match(r"\S+@\S+\.\S+", x) or "格式无效"
).ask()
- 解析:通过
validate
参数实现正则验证,返回错误提示 - 安全场景:数据录入合法性校验
7. 条件跳转问题流
has_account = questionary.confirm("是否已有账户?").ask()
if not has_account:
questionary.text("请输入手机号:").ask()
questionary.password("设置密码:").ask()
else:
questionary.text("输入手机号:").ask()
questionary.password("输入密码:").ask()
- 解析:通过
confirm
类型控制问题分支逻辑 - 业务场景:登录/注册流程切换
高级应用
高级示例:项目初始化向导
python
Copy Code
import os
import asyncio
from pathlib import Path
import questionary
from questionary import Validator, ValidationError
from rich.console import Console
# 自定义验证器:检查项目名称合法性
class ProjectNameValidator(Validator):
def validate(self, value):
if not value.strip():
raise ValidationError(message="项目名称不能为空")
if not value.isidentifier():
raise ValidationError(message="必须是合法Python标识符")
if Path(value).exists():
raise ValidationError(message="目录已存在")
# 异步生成配置文件
async def generate_config(answers):
await asyncio.sleep(1) # 模拟耗时操作
config = f"""
[project]
name = {answers['name']}
type = {answers['type']}
framework = {answers.get('framework', 'none')}
"""
Path(f"{answers['name']}/config.ini").write_text(config)
# 主流程
async def main():
console = Console()
console.print("[bold cyan]🐍 项目初始化向导[/bold cyan]\n")
# 动态问题流
answers = await questionary.prompt([
{
'type': 'text',
'name': 'name',
'message': '项目名称',
'validate': ProjectNameValidator,
'qmark': '🔧'
},
{
'type': 'select',
'name': 'type',
'message': '项目类型',
'choices': ['Web应用', 'CLI工具', '数据分析'],
'when': lambda ans: ans['name'] is not None
},
{
'type': 'select',
'name': 'framework',
'message': '选择框架',
'choices': lambda ans:
['Django', 'Flask'] if ans['type'] == 'Web应用'
else ['Typer', 'Click'],
'when': lambda ans: ans['type'] in ['Web应用', 'CLI工具']
},
{
'type': 'confirm',
'name': 'add_docs',
'message': '添加文档支持?',
'default': True,
'qmark': '📚'
}
]).async_ask()
# 生成文件
with console.status("[bold green]生成项目中..."):
await generate_config(answers)
console.print(f"\n[bold green]✅ 项目 {answers['name']} 创建成功![/bold green]")
console.print(f"👉 运行: [code]cd {answers['name']}[/code]")
if __name__ == "__main__":
asyncio.run(main())
功能解析
-
动态问题流
- 使用
when
参数控制问题显示条件 - 当选择 “Web应用” 时显示框架选项,其他类型显示不同选项
- 项目名称验证失败自动重新提问
- 使用
-
混合交互类型
- 结合
text
,select
,confirm
多种问题类型 - 使用自定义验证器
ProjectNameValidator
- 结合
-
异步处理
- 使用
async_ask()
进行异步提问 - 文件生成时显示加载状态指示器
- 使用
-
美化输出
- 集成
rich
库实现彩色输出和状态动画 - 使用表情符号图标增强可读性
- 集成
-
实际文件操作
- 根据用户输入生成配置文件
- 检查目录是否存在避免覆盖
🐍 项目初始化向导
🔧 项目名称: my_cli_project
? 项目类型: CLI工具
? 选择框架: Typer
📚 添加文档支持? Yes
✅ 项目 my_cli_project 创建成功!
👉 运行: cd my_cli_project
高级技巧总结
-
动态问题控制
- 使用
when
参数实现条件分支 - 通过
lambda
函数访问之前的答案
- 使用
-
异步优化
- 在长时间操作中使用
async_ask()
避免阻塞 - 结合
asyncio.gather()
可并行处理多任务
- 在长时间操作中使用
-
企业级验证
- 继承
Validator
类创建复杂验证逻辑 - 可集成数据库检查等外部验证
- 继承
-
UI/UX 增强
- 使用
rich
或prompt-toolkit
扩展界面 - 通过
qmark
和style
参数定制图标样式
- 使用
此示例展示了如何构建一个生产级 CLI 工具初始化流程,适合需要复杂交互的企业应用开发场景。