11 minutes
综合实战:构建命令行工具
欢迎来到本系列的最后一个项目!经过前面 29 篇文章的学习,你已经掌握了 Python 的方方面面。现在是时候把所有知识串联起来,从零构建一个完整的命令行工具了。
项目概览:任务管理器 CLI
我们将构建一个"任务管理器"(Task Manager)CLI 工具,它具备以下功能:
task-cli add "学习 Python 装饰器" --priority high # 添加任务
task-cli list # 列出所有任务
task-cli list --status pending # 按状态筛选
task-cli done 1 # 完成任务 #1
task-cli delete 1 # 删除任务 #1
task-cli show 1 # 查看任务详情
技术栈:纯 Python 标准库 + argparse + dataclasses + JSON 文件持久化。不需要任何第三方依赖。
第 1 步:项目结构
task-cli/
├── src/
│ └── task_cli/
│ ├── __init__.py
│ ├── __main__.py # python -m task_cli 入口
│ ├── models.py # 数据模型
│ ├── storage.py # 数据持久化
│ ├── cli.py # 命令行接口
│ └── formatter.py # 格式化输出
├── tests/
│ ├── __init__.py
│ ├── test_models.py
│ ├── test_storage.py
│ └── test_cli.py
├── pyproject.toml
└── README.md
创建项目目录结构:
mkdir -p task-cli/src/task_cli
mkdir -p task-cli/tests
touch task-cli/src/task_cli/__init__.py
touch task-cli/tests/__init__.py
第 2 步:数据模型
使用 dataclasses 定义任务的数据模型:
# src/task_cli/models.py
from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import Optional
class TaskStatus(str, Enum):
"""任务状态枚举"""
PENDING = "pending"
COMPLETED = "completed"
class Priority(str, Enum):
"""优先级枚举"""
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
@dataclass
class Task:
"""任务数据模型"""
id: int
title: str
description: str = ""
status: TaskStatus = TaskStatus.PENDING
priority: Priority = Priority.MEDIUM
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
updated_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
def complete(self) -> None:
"""将任务标记为已完成"""
self.status = TaskStatus.COMPLETED
self.updated_at = datetime.now(timezone.utc)
def update(self, **kwargs) -> None:
"""更新任务属性"""
for key, value in kwargs.items():
if hasattr(self, key) and value is not None:
setattr(self, key, value)
self.updated_at = datetime.now(timezone.utc)
def to_dict(self) -> dict:
"""转换为字典(用于 JSON 序列化)"""
return {
"id": self.id,
"title": self.title,
"description": self.description,
"status": self.status.value,
"priority": self.priority.value,
"created_at": self.created_at.isoformat(),
"updated_at": self.updated_at.isoformat(),
}
@classmethod
def from_dict(cls, data: dict) -> "Task":
"""从字典创建 Task 实例(JSON 反序列化)"""
return cls(
id=data["id"],
title=data["title"],
description=data.get("description", ""),
status=TaskStatus(data.get("status", "pending")),
priority=Priority(data.get("priority", "medium")),
created_at=datetime.fromisoformat(data["created_at"]),
updated_at=datetime.fromisoformat(data["updated_at"]),
)
def __str__(self) -> str:
status_mark = "✅" if self.status == TaskStatus.COMPLETED else "⬜"
priority_tag = {
Priority.LOW: "🟢",
Priority.MEDIUM: "🟡",
Priority.HIGH: "🔴",
Priority.CRITICAL: "💀",
}[self.priority]
return f"{status_mark} [{self.id:>3}] {priority_tag} {self.title}"
第 3 步:JSON 存储层
任务数据持久化到本地 JSON 文件:
# src/task_cli/storage.py
import json
import os
from pathlib import Path
from typing import Optional
from .models import Task
class TaskStorage:
"""任务数据持久化管理器"""
def __init__(self, filepath: Optional[str] = None):
if filepath:
self.filepath = Path(filepath)
else:
# 默认保存在用户目录下的 .task-cli/tasks.json
self.filepath = Path.home() / ".task-cli" / "tasks.json"
self._ensure_directory()
def _ensure_directory(self) -> None:
"""确保存储目录存在"""
self.filepath.parent.mkdir(parents=True, exist_ok=True)
def _read_all(self) -> list[dict]:
"""读取所有任务(原始字典格式)"""
if not self.filepath.exists():
return []
try:
with open(self.filepath, "r", encoding="utf-8") as f:
return json.load(f)
except (json.JSONDecodeError, OSError):
return []
def _write_all(self, tasks: list[dict]) -> None:
"""写入所有任务"""
with open(self.filepath, "w", encoding="utf-8") as f:
json.dump(tasks, f, ensure_ascii=False, indent=2)
def add(self, task: Task) -> Task:
"""添加新任务"""
tasks = self._read_all()
tasks.append(task.to_dict())
self._write_all(tasks)
return task
def get_all(self) -> list[Task]:
"""获取所有任务"""
return [Task.from_dict(d) for d in self._read_all()]
def get_by_id(self, task_id: int) -> Optional[Task]:
"""根据 ID 获取单个任务"""
tasks = self._read_all()
for data in tasks:
if data["id"] == task_id:
return Task.from_dict(data)
return None
def update(self, task_id: int, **kwargs) -> Optional[Task]:
"""更新任务"""
tasks = self._read_all()
for data in tasks:
if data["id"] == task_id:
task = Task.from_dict(data)
task.update(**kwargs)
tasks[tasks.index(data)] = task.to_dict()
self._write_all(tasks)
return task
return None
def delete(self, task_id: int) -> bool:
"""删除任务"""
tasks = self._read_all()
filtered = [t for t in tasks if t["id"] != task_id]
if len(filtered) == len(tasks):
return False # 未找到
self._write_all(filtered)
return True
def get_next_id(self) -> int:
"""生成下一个可用的任务 ID"""
tasks = self._read_all()
if not tasks:
return 1
return max(t["id"] for t in tasks) + 1
def clear(self) -> None:
"""清空所有任务(用于测试)"""
self._write_all([])
第 4 步:格式化输出
# src/task_cli/formatter.py
from typing import Optional
from .models import Task, TaskStatus, Priority
def format_task_detail(task: Task) -> str:
"""格式化任务详情"""
status_text = "已完成" if task.status == TaskStatus.COMPLETED else "待办"
priority_names = {
Priority.LOW: "低",
Priority.MEDIUM: "中",
Priority.HIGH: "高",
Priority.CRITICAL: "紧急",
}
lines = [
f"任务 #{task.id}",
"─" * 40,
f"标题: {task.title}",
f"描述: {task.description or '(无描述)'}",
f"状态: {status_text}",
f"优先级: {priority_names[task.priority]}",
f"创建时间: {task.created_at.strftime('%Y-%m-%d %H:%M:%S')}",
f"更新时间: {task.updated_at.strftime('%Y-%m-%d %H:%M:%S')}",
]
return "\n".join(lines)
def format_task_list(
tasks: list[Task],
status: Optional[TaskStatus] = None,
) -> str:
"""格式化任务列表"""
if not tasks:
return "📭 还没有任务,使用 task-cli add 添加一个吧!"
# 按状态筛选
if status:
tasks = [t for t in tasks if t.status == status]
if not tasks:
status_text = "已完成" if status == TaskStatus.COMPLETED else "待办"
return f"📭 没有{status_text}任务。"
lines = [f"📋 共 {len(tasks)} 个任务:", ""]
for task in tasks:
lines.append(f" {task}")
return "\n".join(lines)
def format_error(message: str) -> str:
"""格式化错误信息"""
return f"❌ 错误: {message}"
def format_success(message: str) -> str:
"""格式化成功信息"""
return f"✅ {message}"
第 5 步:CLI 接口
使用 argparse 构建命令行接口:
# src/task_cli/cli.py
import argparse
import sys
from .models import Task, TaskStatus, Priority
from .storage import TaskStorage
from .formatter import (
format_task_detail,
format_task_list,
format_error,
format_success,
)
def create_parser() -> argparse.ArgumentParser:
"""创建命令行参数解析器"""
parser = argparse.ArgumentParser(
prog="task-cli",
description="📋 任务管理器 - 在终端中管理你的任务",
epilog="使用 task-cli <command> --help 查看子命令帮助",
)
subparsers = parser.add_subparsers(dest="command", help="可用命令")
# add 子命令
add_parser = subparsers.add_parser("add", help="添加新任务")
add_parser.add_argument("title", help="任务标题")
add_parser.add_argument("-d", "--description", default="", help="任务描述")
add_parser.add_argument(
"-p", "--priority",
choices=["low", "medium", "high", "critical"],
default="medium",
help="优先级(默认: medium)",
)
# list 子命令
list_parser = subparsers.add_parser("list", help="列出任务")
list_parser.add_argument(
"-s", "--status",
choices=["pending", "completed"],
help="按状态筛选",
)
# show 子命令
show_parser = subparsers.add_parser("show", help="查看任务详情")
show_parser.add_argument("id", type=int, help="任务 ID")
# done 子命令
done_parser = subparsers.add_parser("done", help="完成任务")
done_parser.add_argument("id", type=int, help="任务 ID")
# update 子命令
update_parser = subparsers.add_parser("update", help="更新任务")
update_parser.add_argument("id", type=int, help="任务 ID")
update_parser.add_argument("-t", "--title", help="新标题")
update_parser.add_argument("-d", "--description", help="新描述")
update_parser.add_argument(
"-p", "--priority",
choices=["low", "medium", "high", "critical"],
help="新优先级",
)
# delete 子命令
delete_parser = subparsers.add_parser("delete", help="删除任务")
delete_parser.add_argument("id", type=int, help="任务 ID")
# clear 子命令
subparsers.add_parser("clear", help="清空所有任务")
return parser
def handle_add(args: argparse.Namespace, storage: TaskStorage) -> int:
"""处理 add 命令"""
try:
task = Task(
id=storage.get_next_id(),
title=args.title,
description=args.description,
priority=Priority(args.priority),
)
storage.add(task)
print(format_success(f"已添加任务 #{task.id}: {task.title}"))
return 0
except (OSError, ValueError) as e:
print(format_error(str(e)))
return 1
def handle_list(args: argparse.Namespace, storage: TaskStorage) -> int:
"""处理 list 命令"""
try:
tasks = storage.get_all()
status_filter = TaskStatus(args.status) if args.status else None
print(format_task_list(tasks, status_filter))
return 0
except (OSError, ValueError) as e:
print(format_error(str(e)))
return 1
def handle_show(args: argparse.Namespace, storage: TaskStorage) -> int:
"""处理 show 命令"""
try:
task = storage.get_by_id(args.id)
if not task:
print(format_error(f"任务 #{args.id} 不存在"))
return 1
print(format_task_detail(task))
return 0
except OSError as e:
print(format_error(str(e)))
return 1
def handle_done(args: argparse.Namespace, storage: TaskStorage) -> int:
"""处理 done 命令"""
try:
task = storage.update(args.id, status=TaskStatus.COMPLETED)
if not task:
print(format_error(f"任务 #{args.id} 不存在"))
return 1
print(format_success(f"任务 #{args.id} 已完成: {task.title}"))
return 0
except OSError as e:
print(format_error(str(e)))
return 1
def handle_update(args: argparse.Namespace, storage: TaskStorage) -> int:
"""处理 update 命令"""
try:
kwargs = {}
if args.title:
kwargs["title"] = args.title
if args.description is not None:
kwargs["description"] = args.description
if args.priority:
kwargs["priority"] = Priority(args.priority)
if not kwargs:
print(format_error("请至少指定一个要更新的字段"))
return 1
task = storage.update(args.id, **kwargs)
if not task:
print(format_error(f"任务 #{args.id} 不存在"))
return 1
print(format_success(f"任务 #{args.id} 已更新: {task.title}"))
return 0
except (OSError, ValueError) as e:
print(format_error(str(e)))
return 1
def handle_delete(args: argparse.Namespace, storage: TaskStorage) -> int:
"""处理 delete 命令"""
try:
if storage.delete(args.id):
print(format_success(f"已删除任务 #{args.id}"))
return 0
else:
print(format_error(f"任务 #{args.id} 不存在"))
return 1
except OSError as e:
print(format_error(str(e)))
return 1
def handle_clear(args: argparse.Namespace, storage: TaskStorage) -> int:
"""处理 clear 命令"""
try:
storage.clear()
print(format_success("已清空所有任务"))
return 0
except OSError as e:
print(format_error(str(e)))
return 1
def main(argv: list[str] | None = None) -> int:
"""主入口函数"""
parser = create_parser()
args = parser.parse_args(argv)
if not args.command:
parser.print_help()
return 0
storage = TaskStorage()
handlers = {
"add": handle_add,
"list": handle_list,
"show": handle_show,
"done": handle_done,
"update": handle_update,
"delete": handle_delete,
"clear": handle_clear,
}
handler = handlers.get(args.command)
if handler:
return handler(args, storage)
return 0
if __name__ == "__main__":
sys.exit(main())
第 6 步:模块入口
# src/task_cli/__main__.py
"""支持 python -m task_cli 运行"""
from .cli import main
if __name__ == "__main__":
import sys
sys.exit(main())
第 7 步:测试 CLI 工具
测试是保证工具可靠性的关键:
# tests/test_models.py
import pytest
from datetime import datetime, timezone
from task_cli.models import Task, TaskStatus, Priority
class TestTaskCreation:
def test_create_minimal_task(self):
"""创建只有必要字段的任务"""
task = Task(id=1, title="测试任务")
assert task.id == 1
assert task.title == "测试任务"
assert task.status == TaskStatus.PENDING
assert task.priority == Priority.MEDIUM
assert task.description == ""
def test_create_full_task(self):
"""创建包含所有字段的任务"""
task = Task(
id=1,
title="重要任务",
description="这是一个重要任务",
status=TaskStatus.COMPLETED,
priority=Priority.HIGH,
)
assert task.description == "这是一个重要任务"
assert task.status == TaskStatus.COMPLETED
assert task.priority == Priority.HIGH
class TestTaskMethods:
def test_complete_task(self):
"""完成一个任务"""
task = Task(id=1, title="测试")
task.complete()
assert task.status == TaskStatus.COMPLETED
def test_update_task(self):
"""更新任务属性"""
task = Task(id=1, title="原标题")
task.update(title="新标题", priority=Priority.HIGH)
assert task.title == "新标题"
assert task.priority == Priority.HIGH
class TestTaskSerialization:
def test_to_dict(self):
"""任务序列化为字典"""
task = Task(id=1, title="测试", priority=Priority.HIGH)
data = task.to_dict()
assert data["id"] == 1
assert data["title"] == "测试"
assert data["priority"] == "high"
assert data["status"] == "pending"
def test_from_dict(self):
"""从字典反序列化任务"""
data = {
"id": 1,
"title": "测试",
"description": "描述",
"status": "completed",
"priority": "high",
"created_at": "2026-05-30T10:00:00+00:00",
"updated_at": "2026-05-30T12:00:00+00:00",
}
task = Task.from_dict(data)
assert task.id == 1
assert task.title == "测试"
assert task.status == TaskStatus.COMPLETED
assert task.priority == Priority.HIGH
def test_roundtrip(self):
"""序列化后再反序列化,结果应一致"""
original = Task(id=42, title="往返测试", priority=Priority.CRITICAL)
data = original.to_dict()
restored = Task.from_dict(data)
assert restored.id == original.id
assert restored.title == original.title
assert restored.priority == original.priority
assert restored.status == original.status
# tests/test_storage.py
import pytest
import json
from pathlib import Path
from task_cli.models import Task, TaskStatus, Priority
from task_cli.storage import TaskStorage
@pytest.fixture
def storage(tmp_path):
"""每个测试使用临时文件存储"""
filepath = tmp_path / "tasks.json"
return TaskStorage(str(filepath))
class TestTaskStorage:
def test_add_task(self, storage):
"""添加任务后应能读取"""
task = Task(id=1, title="测试任务")
storage.add(task)
tasks = storage.get_all()
assert len(tasks) == 1
assert tasks[0].title == "测试任务"
def test_get_by_id(self, storage):
"""按 ID 获取任务"""
task = Task(id=1, title="任务一")
storage.add(task)
found = storage.get_by_id(1)
assert found is not None
assert found.title == "任务一"
missing = storage.get_by_id(999)
assert missing is None
def test_update_task(self, storage):
"""更新任务"""
storage.add(Task(id=1, title="旧标题"))
updated = storage.update(1, title="新标题", priority=Priority.HIGH)
assert updated is not None
assert updated.title == "新标题"
# 验证持久化
task = storage.get_by_id(1)
assert task.title == "新标题"
assert task.priority == Priority.HIGH
def test_delete_task(self, storage):
"""删除任务"""
storage.add(Task(id=1, title="将被删除"))
assert storage.delete(1) is True
assert storage.get_by_id(1) is None
def test_delete_nonexistent(self, storage):
"""删除不存在的任务应返回 False"""
assert storage.delete(999) is False
def test_next_id(self, storage):
"""生成正确的下一个 ID"""
assert storage.get_next_id() == 1
storage.add(Task(id=5, title="ID 5"))
assert storage.get_next_id() == 6
storage.add(Task(id=10, title="ID 10"))
assert storage.get_next_id() == 11
def test_clear(self, storage):
"""清空所有任务"""
storage.add(Task(id=1, title="任务一"))
storage.add(Task(id=2, title="任务二"))
storage.clear()
assert len(storage.get_all()) == 0
def test_persistence(self, storage):
"""数据应持久化到文件"""
storage.add(Task(id=1, title="持久化测试"))
# 创建新的 storage 实例,从同一个文件读取
storage2 = TaskStorage(str(storage.filepath))
tasks = storage2.get_all()
assert len(tasks) == 1
assert tasks[0].title == "持久化测试"
def test_empty_storage(self, storage):
"""空存储返回空列表"""
assert storage.get_all() == []
def test_corrupted_file(self, storage):
"""损坏的文件应被优雅处理"""
storage.filepath.write_text("这不是 JSON", encoding="utf-8")
assert storage.get_all() == []
第 8 步:打包发布
创建 pyproject.toml 使工具可安装:
[project]
name = "task-cli"
version = "1.0.0"
description = "一个终端任务管理器"
readme = "README.md"
requires-python = ">=3.10"
authors = [
{name = "Python 从入门到精通", email = "learner@example.com"},
]
[project.scripts]
task-cli = "task_cli.cli:main"
[build-system]
requires = ["setuptools>=68.0"]
build-backend = "setuptools.build_meta"
[tool.setuptools.packages.find]
where = ["src"]
[tool.pytest.ini_options]
testpaths = ["tests"]
安装到当前环境:
# 开发模式安装(可编辑)
pip install -e .
# 安装后可以直接使用
task-cli --help
task-cli add "学习 Python 30 篇"
第 9 步:使用体验
安装完成后,来看看实际运行效果:
# 查看帮助
$ task-cli --help
usage: task-cli [-h] {add,list,show,done,update,delete,clear} ...
📋 任务管理器 - 在终端中管理你的任务
positional arguments:
{add,list,show,done,update,delete,clear}
add 添加新任务
list 列出任务
show 查看任务详情
done 完成任务
update 更新任务
delete 删除任务
clear 清空所有任务
# 添加任务
$ task-cli add "完成 Python 课程项目" -d "实现任务管理器 CLI" -p high
✅ 已添加任务 #1: 完成 Python 课程项目
$ task-cli add "学习 pytest 高级用法" -p medium
✅ 已添加任务 #2: 学习 pytest 高级用法
$ task-cli add "写一篇技术博客" -d "总结 Python 学习心得" -p low
✅ 已添加任务 #3: 写一篇技术博客
$ task-cli add "修复 bug #1234" -p critical
✅ 已添加任务 #4: 修复 bug #1234
# 列出所有任务
$ task-cli list
📋 共 4 个任务:
⬜ [ 1] 🔴 完成 Python 课程项目
⬜ [ 2] 🟡 学习 pytest 高级用法
⬜ [ 3] 🟢 写一篇技术博客
⬜ [ 4] 💀 修复 bug #1234
# 完成任务
$ task-cli done 4
✅ 任务 #4 已完成: 修复 bug #1234
$ task-cli done 1
✅ 任务 #1 已完成: 完成 Python 课程项目
# 只查看待办任务
$ task-cli list --status pending
📋 共 2 个任务:
⬜ [ 2] 🟡 学习 pytest 高级用法
⬜ [ 3] 🟢 写一篇技术博客
# 查看已完成任务
$ task-cli list --status completed
📋 共 2 个任务:
✅ [ 1] 🔴 完成 Python 课程项目
✅ [ 4] 💀 修复 bug #1234
# 查看任务详情
$ task-cli show 1
任务 #1
────────────────────────────────────────
标题: 完成 Python 课程项目
描述: 实现任务管理器 CLI
状态: 已完成
优先级: 高
创建时间: 2026-05-30 10:00:00
更新时间: 2026-05-30 10:30:00
# 更新任务
$ task-cli update 3 -t "写一篇 Python 技术博客" -p medium
✅ 任务 #3 已更新: 写一篇 Python 技术博客
# 删除任务
$ task-cli delete 3
✅ 已删除任务 #3
完整运行所有测试:
$ pytest -v
============================== test session starts ==============================
collected 15 items
tests/test_models.py::TestTaskCreation::test_create_minimal_task PASSED
tests/test_models.py::TestTaskCreation::test_create_full_task PASSED
tests/test_models.py::TestTaskMethods::test_complete_task PASSED
tests/test_models.py::TestTaskMethods::test_update_task PASSED
tests/test_models.py::TestTaskSerialization::test_to_dict PASSED
tests/test_models.py::TestTaskSerialization::test_from_dict PASSED
tests/test_models.py::TestTaskSerialization::test_roundtrip PASSED
tests/test_storage.py::TestTaskStorage::test_add_task PASSED
tests/test_storage.py::TestTaskStorage::test_get_by_id PASSED
tests/test_storage.py::TestTaskStorage::test_update_task PASSED
tests/test_storage.py::TestTaskStorage::test_delete_task PASSED
tests/test_storage.py::TestTaskStorage::test_delete_nonexistent PASSED
tests/test_storage.py::TestTaskStorage::test_next_id PASSED
tests/test_storage.py::TestTaskStorage::test_clear PASSED
tests/test_storage.py::TestTaskStorage::test_persistence PASSED
tests/test_storage.py::TestTaskStorage::test_empty_storage PASSED
tests/test_storage.py::TestTaskStorage::test_corrupted_file PASSED
============================== 17 passed in 0.15s ===============================
扩展方向
我们的任务管理器已经功能完整,但还可以继续扩展:
| 功能 | 实现思路 |
|---|---|
| 颜色输出 | 使用 colorama 或 ANSI 转义码美化输出 |
| 搜索功能 | task-cli search "关键词" 按标题/描述搜索 |
| 标签系统 | 为任务添加标签:task-cli add "..." --tags python,blog |
| 截止日期 | 添加截止日期,支持 --due 2026-06-30 |
| 数据导出 | task-cli export 导出为 CSV 或 Markdown |
| 交互模式 | 使用 rich 或 textual 构建 TUI 界面 |
| 同步功能 | 将任务同步到云端或 Notion |
回顾:30 篇文章的旅程
从 5 月 1 日的第一篇到今天的最后一篇,我们已经走过了漫长的学习之路。让我们回头看看这一路都学到了什么:
基础入门篇(1-8)
构建了 Python 的基石:语法、变量、数据类型(字符串、列表、字典、集合)、条件判断和循环。从这开始,你已经能写简单的脚本了。
函数与模块篇(9-14)
掌握了函数定义、参数传递、作用域、闭包、Lambda。学会了模块化组织和文件操作,了解了异常处理的重要性。代码不再是平铺直叙的脚本,开始有了结构。
面向对象篇(15-20)
学习了类与对象、继承与多态、魔法方法、属性装饰器。理解了上下文管理器(with 语句)和迭代器/生成器。你的代码拥有了面向对象的表达能力。
高级特性篇(21-26)
深入装饰器、正则表达式、日期时间处理、标准库精讲、并发编程(多线程/多进程)和异步编程(asyncio)。这些特性让 Python 开发者从"能用"进阶到"精通"。
工程实战篇(27-30)
- 第 27 章:学会用
unittest和pytest为代码写测试 - 第 28 章:掌握虚拟环境(
venv、Poetry、uv)和依赖管理 - 第 29 章:学会用
requests调用网络 API,与互联网世界交互 - 第 30 章:综合运用所有知识,从零构建了一个完整的 CLI 工具
从新手到工程实践
30 篇文章,覆盖了从"你好世界"到完整的命令行工具开发。你现在掌握的不仅仅是 Python 语法,而是一整套工程实践能力:
┌─────────────────────────────────┐
│ 工程实践(27-30) │
│ 测试 · 环境 · 网络 · 项目 │
├─────────────────────────────────┤
│ 高级特性(21-26) │
│ 装饰器 · 正则 · 并发 · 异步 │
├─────────────────────────────────┤
│ 面向对象(15-20) │
│ 类 · 继承 · 魔法方法 · 迭代器 │
├─────────────────────────────────┤
│ 函数与模块(9-14) │
│ 函数 · 模块 · 文件 · 异常 │
├─────────────────────────────────┤
│ 基础入门(1-8) │
│ 语法 · 变量 · 数据结构 · 循环 │
└─────────────────────────────────┘
下一步去向何方?
课程结束了,但编程之路才刚刚开始。以下是一些你可以继续探索的方向:
- Web 开发:FastAPI / Django —— 用 Python 构建 Web 应用
- 数据分析:pandas / numpy / matplotlib —— 从数据中洞察价值
- 自动化:Selenium / Playwright —— 写脚本自动化一切重复工作
- 机器学习:scikit-learn / PyTorch —— 让程序具备智能
- 开源贡献:给喜欢的 Python 项目提交 PR —— 在实践中成长
小结
本章我们从零构建了一个完整的任务管理器 CLI 工具,实现了:
- 项目结构:清晰的分层架构,模型(models)、存储(storage)、格式化(formatter)、CLI 接口(cli)各司其职
- 数据模型:使用
dataclasses定义 Task 类,支持序列化为 JSON 和从 JSON 恢复 - 数据持久化:基于 JSON 文件的存储层,CRUD 操作完整
- CLI 接口:使用
argparse构建专业的命令行界面,包括子命令和参数 - 格式化输出:友好的用户界面,emoji 状态标识,清晰的信息展示
- 测试覆盖:使用
pytest为模型层和存储层编写了完整的测试 - 可安装包:通过
pyproject.toml打包,pip install -e .一键安装
最重要的是,这个项目综合运用了本系列所有核心知识:
- 函数与模块(第 9-12 章)
- 异常处理(第 14 章)
- 类与数据类(第 15、18 章)
- 文件 I/O(第 13 章)
- 日期时间处理(第 23 章)
- JSON 序列化(第 24 章)
- 测试(第 27 章)
- 依赖管理(第 28 章)
- 错误处理(第 14 章)
学习编程最好的方式就是动手写代码。 不是因为看了 30 篇文章就学会了,而是因为在这过程中,你亲自敲了每一行代码、调试了每一个 bug、理解了每一个概念。
现在,去创造属于你自己的 Python 项目吧。🚀
Summary: 30 篇系列收官之作——从零构建任务管理器 CLI,回顾完整学习旅程。