Day 30:综合练习------个人笔记管理器 & 第一阶段总结
第一阶段最后一天,做一个完整的笔记管理器,然后回顾这 30 天我们学到了什么。
一、笔记管理器------功能需求
- 创建 Markdown 笔记(自动生成文件名)
- 列出所有笔记
- 按关键词搜索笔记
- 查看/编辑笔记
- 给笔记加标签
- 按标签筛选
- 所有笔记存储在本地文件夹中
二、完整代码
python
"""
个人笔记管理器
笔记存储在 ./notes 文件夹中,元数据存储在 notes.json
"""
import json
import re
from datetime import datetime
from pathlib import Path
class Note:
"""一篇笔记"""
def __init__(self, title, content="", tags=None):
self.title = title
self.content = content
self.tags = tags or []
self.created_at = datetime.now().isoformat()
self.updated_at = self.created_at
self.filename = self._make_filename(title)
@staticmethod
def _make_filename(title):
"""把标题转成安全的文件名"""
safe = re.sub(r"[^\w\s-]", "", title) # 去掉特殊字符
safe = re.sub(r"\s+", "_", safe.strip()) # 空格转下划线
return f"{safe}.md"
def update_content(self, content):
self.content = content
self.updated_at = datetime.now().isoformat()
def add_tag(self, tag):
if tag not in self.tags:
self.tags.append(tag)
def matches_search(self, keyword):
"""搜索标题和内容"""
kw = keyword.lower()
return kw in self.title.lower() or kw in self.content.lower()
def to_dict(self):
return {
"title": self.title,
"tags": self.tags,
"filename": self.filename,
"created_at": self.created_at,
"updated_at": self.updated_at,
}
@classmethod
def from_dict(cls, data, content=""):
note = cls(data["title"], content, data.get("tags", []))
note.filename = data["filename"]
note.created_at = data["created_at"]
note.updated_at = data.get("updated_at", data["created_at"])
return note
class NoteManager:
"""笔记管理器"""
def __init__(self, notes_dir="notes"):
self.notes_dir = Path(notes_dir)
self.meta_file = self.notes_dir / "notes.json"
self.notes = [] # Note 对象列表
self._init_storage()
self.load()
def _init_storage(self):
self.notes_dir.mkdir(exist_ok=True)
if not self.meta_file.exists():
self.meta_file.write_text('{"notes": []}', encoding="utf-8")
def load(self):
"""加载元数据和笔记内容"""
try:
meta = json.loads(self.meta_file.read_text(encoding="utf-8"))
for item in meta.get("notes", []):
note_file = self.notes_dir / item["filename"]
content = note_file.read_text(encoding="utf-8") if note_file.exists() else ""
self.notes.append(Note.from_dict(item, content))
except (json.JSONDecodeError, KeyError):
self.notes = []
def save(self):
"""保存元数据"""
meta = {"notes": [n.to_dict() for n in self.notes]}
self.meta_file.write_text(
json.dumps(meta, ensure_ascii=False, indent=2),
encoding="utf-8",
)
def create(self, title, content=""):
"""创建笔记"""
note = Note(title, content)
self.notes.append(note)
self._write_note_file(note)
self.save()
print(f"创建笔记:{note.title}")
return note
def _write_note_file(self, note):
"""把笔记内容写入文件"""
filepath = self.notes_dir / note.filename
filepath.write_text(note.content, encoding="utf-8")
def list_all(self):
"""列出所有笔记"""
if not self.notes:
print("还没有笔记,来创建第一篇吧!")
return
print(f"\n共 {len(self.notes)} 篇笔记:")
for i, note in enumerate(self.notes, 1):
tags = f"[{', '.join(note.tags)}]" if note.tags else ""
preview = note.content[:40].replace("\n", " ") + ("..." if len(note.content) > 40 else "")
print(f" {i}. {note.title} {tags}")
if preview:
print(f" {preview}")
def search(self, keyword):
"""搜索笔记"""
results = [n for n in self.notes if n.matches_search(keyword)]
if not results:
print(f"没有找到包含 '{keyword}' 的笔记")
return
print(f"\n找到 {len(results)} 篇包含 '{keyword}' 的笔记:")
for note in results:
print(f" - {note.title}")
def view(self, title_or_index):
"""查看笔记"""
note = self._find_note(title_or_index)
if not note:
return
print(f"\n{'=' * 50}")
print(f"标题:{note.title}")
print(f"标签:{', '.join(note.tags) if note.tags else '无'}")
print(f"更新:{note.updated_at[:19]}")
print(f"{'=' * 50}")
print(note.content if note.content else "(空内容)")
print("=" * 50)
def edit(self, title_or_index):
"""编辑笔记"""
note = self._find_note(title_or_index)
if not note:
return
print(f"正在编辑:{note.title}")
print("输入新内容(输入 END 结束):")
lines = []
while True:
line = input()
if line == "END":
break
lines.append(line)
note.update_content("\n".join(lines))
self._write_note_file(note)
self.save()
print("笔记已更新!")
def _find_note(self, key):
"""按标题或序号查找笔记"""
for note in self.notes:
if note.title == key:
return note
try:
idx = int(key) - 1
if 0 <= idx < len(self.notes):
return self.notes[idx]
except ValueError:
pass
print(f"找不到笔记:{key}")
return None
def run(self):
"""主循环"""
while True:
print("\n" + "=" * 50)
print("📝 笔记管理器")
print("=" * 50)
print(" 1. 新建笔记 2. 查看列表 3. 搜索")
print(" 4. 查看内容 5. 编辑内容 6. 退出")
print("-" * 50)
choice = input("选择:").strip()
try:
if choice == "1":
title = input("标题:")
self.create(title)
elif choice == "2":
self.list_all()
elif choice == "3":
kw = input("搜索关键词:")
self.search(kw)
elif choice == "4":
self.view(input("标题或序号:"))
elif choice == "5":
self.edit(input("标题或序号:"))
elif choice == "6":
print("再见!")
break
except Exception as e:
print(f"出错:{e}")
if __name__ == "__main__":
NoteManager().run()
三、第一阶段回顾
30 天前的我们 vs 现在的我们:
| 阶段 | 天数 | 核心内容 |
|---|---|---|
| 基础语法 | Day 1-12 | 变量、数据类型、字符串、列表、字典、集合、条件、循环 |
| 函数 | Day 13-15 | 函数定义、参数、作用域、lambda |
| 文件操作 | Day 16-18 | 文件读写、CSV、JSON、pathlib |
| 错误处理 | Day 19-21 | try/except、raise、调试技巧 |
| 模块与包 | Day 22-24 | import、包结构、pip、标准库、第三方库 |
| 面向对象 | Day 25-27 | 类与对象、继承、封装、多态、特殊方法 |
| 综合实战 | Day 28-30 | Todo应用、数据分析工具、笔记管理器 |
从一行 print("Hello World") 到自己写出完整的命令行应用,这就是 30 天的力量。
四、明天学什么?
第一阶段 Python 基础结束。明天正式进入第二阶段:数据科学工具 ------从 NumPy 开始。NumPy 是整个 Python 数据科学和 AI 生态的基石。
30天的积累,你已经不是"零基础"了。后面的路是站在这个基础上往上走------学 NumPy、Pandas,然后走进机器学习和深度学习的大门。
第30天,打卡完成。里程碑达成!
本系列是个人学习笔记,如有错误欢迎在评论区指正交流。