AI智能体筑基:Python类封装,为 RAG/Agent 类打基础(代码是Day02的文件配置)
Day03 AI智能体筑基打卡
当 Python 首次登顶 TIOBE 榜首、取代霸榜多年的 Java,AI 时代的编程版图已然改写。语法易学只是入场券,真正的分水岭在于智能体应用开发中的落地能力。无论你是在校园里学着与现实脱节的旧知识,还是身处传统前后端领域面临被替代的焦虑——这个系列不绕弯子、不讲废话,只聚焦那些真正会卡住你的痛点,记录一步步踩坑与补全认知的过程。
AI 浪潮下,我们都是摸着石头过河的同行者。与其被焦虑裹挟,不如把学习日常摊开来,一起查缺补漏、扎实成长。希望这些记录能陪你在这场技术变革中,走得更稳、更远。
核心目标:用类封装关联功能,为后续 RAG/Agent 类打基础。
一、今日学习内容
类与实例、构造函数__init__
类:描述一组具有相同属性和方法的模板。(图纸,没有实体)
实例(对象):是基于类创建出来的,有属性和方法,创建对象的过程也叫对象的实例化。(产品,有实体,可以有无数个)
__init__:构造方法,基于类创建对象的时候,会自动调用此方法。(根据图纸造产品的方法,自动调用)
属性:属于对象的变量。
方法:属于对象的方法,定义语法与函数一致。
class Dog:
# 构造函数:造实例时自动触发,self=当前实例
def __init__(self, name, age):
self.name = name # 绑定属性
self.age = age
# 普通方法
def bark(self):
print(f"{self.name} 叫了一声,{self.age}岁")
# 造实例(触发 __init__)
dog1 = Dog("旺财", 3)
dog2 = Dog("小黑", 5)
# 调用
dog1.bark() # 旺财 叫了一声,3岁
dog2.bark() # 小黑 叫了一声,5岁
注:一个类可以创建无数个对象,self是必传参数,表示当前创建的实例对象(是对象再类中的代表)。
注:类名的命名规范,遵循大驼峰命名法。
私有属性、封装原则、对外接口设计(黑匣子原理)
私有属性:私有的属性和方法只能在类的内部使用; Python中并没有真正的私有机制,约定在私有属性名和方法名前加__(两个下划线)。
封装:将数据(属性)及操作数据的方法绑定在同一个类结构中,对外隐藏内部实现细节,仅暴露必要的公共接口供外部访问。
对外接口:外部想要调用封装的方法或数据,只能通过类的对外接口调用。
class BankAccount:
def __init__(self, balance):
self.__balance = balance # 私有属性(双下划线,外面动不了)
def deposit(self, amount): # 对外接口1:存钱
if amount > 0:
self.__balance += amount
def get_balance(self): # 对外接口2:查余额(只读,不能改)
return self.__balance # 大部分读取私有属性都会用get方法
# 使用
acc = BankAccount(1000)
acc.deposit(500) # 通过接口存钱
print(acc.get_balance()) # 通过接口查余额:1500
print(acc.__balance) # 报错!直接访问私有属性,外面碰不到
为什么要封装:封装将数据(属性)和操作数据的方法捆绑为独立单元,通过隐藏内部实现细节、仅暴露公共接口,达到隔离变化、保护数据完整性、降低耦合的目的。外部不关心内部怎么算的,只管调用接口就行,内部改动不影响外部调用代码。
单一职责类设计方法
和单一职责函数一样,一个萝卜一个坑。
核心思想:一个类,只干且必须干好一件事。
特点:单一职责写出来的类,一看类名就知道是做什么的,通常也很短,用起来方便,保证代码逻辑清晰,低耦合,十分的优雅。
二、今日核心代码
"""
文件工具类:支持 TXT/MD 读取、JSON 写入
参考开源项目的文件操作封装模式
"""
from pathlib import Path # 导入Path类,用于跨平台路径操作
from typing import Optional # 导入Optional类型提示(实际未使用)
from .exceptions import FileOperateException # 导入自定义文件操作异常类
class FileUtil:
"""文件读写、路径处理工具,基于pathlib,跨平台兼容"""
@staticmethod # 装饰器,声明一个静态方法
def get_project_root() -> Path:
"""获取项目根目录"""
return Path(__file__).parent.parent
@staticmethod
def safe_read(file_path: str | Path, encoding: str = "utf‑8") -> str:
"""安全读取文本文件"""
fp = Path(file_path) # 转换为Path对象,统一处理
if not fp.exists(): # 检查路径是否纯在
raise FileOperateException(message=f"文件不存在:{fp}") # 抛异常
if not fp.is_file(): # 检查是否为普通文件
raise FileOperateException(message=f"不是合法文件:{fp}") # 继续抛异常
try:
return fp.read_text(encoding=encoding) # 读取全部文件内容
except Exception as e: # 捕获所有异常(兜底)
raise FileOperateException(message=f"读取失败:{str(e)}") from e # 还是抛出异常
@staticmethod
def safe_write(file_path: str | Path, content: str, encoding: str = "utf‑8") -> None:
"""写入文件,不存在自动创建父目录"""
fp = Path(file_path)
fp.parent.mkdir(parents=True, exist_ok=True) # 父目录不存在则递归创建
try:
fp.write_text(content, encoding=encoding) # 写入文本
except Exception as e:
raise FileOperateException(message=f"写入失败:{str(e)}") from e
@staticmethod
def safe_append(file_path: str | Path, content: str, encoding: str = "utf‑8") -> None:
"""追加写入"""
fp = Path(file_path)
fp.parent.mkdir(parents=True, exist_ok=True)
old = ""
if fp.exists():
old = fp.read_text(encoding=encoding)
FileUtil.safe_write(fp, old + content, encoding=encoding) # 将新旧内容整体写入
三、每日三件事
-
今日代码实操完成情况: 完成文件工具 + 配置工具,跑通读写测试
-
今日踩坑Bug+原因+解决方案:
程序在 PyCharm 点击运行正常;在终端命令行运行直接报文件不存在。
# 错误写法,写死相对字符串 fp = Path("./data/test.txt")PyCharm 默认工作目录是项目根目录;终端 cd 到别的目录执行脚本,工作目录就变了,
./指向就错,直接抛FileOperateException。# 正确写法 @staticmethod def get_project_root() -> Path: # 根据当前file_utils.py文件位置向上找根目录,不受运行目录影响 return Path(__file__).parent.parent面试可以这么说:
“做文件工具封装时踩过相对路径大坑,直接写
./依赖运行时工作目录,终端运行就失效。我用__file__拿到 py 文件真实位置,向上推导项目根目录,所有路径基于根目录拼接,彻底隔离运行目录差异。同时统一处理父目录自动创建、强制 utf‑8 编码、区分文件与文件夹判断,把这些重复逻辑封装进 file_utils,上层业务代码只调用工具方法,不用关心底层文件细节。”
-
GitHub当日代码仓库地址: https://github.com/Youlan514/AI_Agent_Basic
四、今日优质代码习惯
一个顶级原则:越早暴露错误,调试成本越低(快失败Fail Fast)。
- 坏习惯:返回
None或False让调用方去猜。 - 好习惯:条件不满足直接
raise。让异常穿透到最外层统一处理,避免错误数据在代码里“游荡”。
更多推荐
所有评论(0)