阶段 1:编程与服务基础

类与对象 / 异常处理 / 文件与 JSON / 模块化与 typing 核心笔记


2. 类与对象

2.1 基本概念

类(class)

类是对一类事物的抽象模板。

对象(object)

对象是类的具体实例。

例如:

  • 类:学生
  • 对象:张三、李四
class Student:
    pass

s1 = Student()
s2 = Student()

2.2 为什么需要类

函数适合封装逻辑;类适合把:

  • 数据
  • 行为

组织到一起。

例如“用户”不仅有:

  • name
  • age

还会有行为:

  • 登录
  • 更新信息

这时用类更自然。


2.3 __init__ 构造方法

对象创建时,通常会执行 __init__ 初始化属性。

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

创建对象:

s = Student("Tom", 20)
print(s.name)
print(s.age)

核心理解

  • self 代表当前对象本身
  • self.name = name 表示把传入参数保存到对象属性上

2.4 实例属性与实例方法

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        return f"我叫{self.name},今年{self.age}岁"

调用:

s = Student("Tom", 20)
print(s.introduce())

核心理解

  • 属性:对象的数据
  • 方法:对象的行为

2.5 self 是什么

self 表示“当前对象”。

class User:
    def __init__(self, name):
        self.name = name

这里:

  • 左边 self.name 是对象属性
  • 右边 name 是传进来的参数

self 不是关键字,但约定俗成必须这么写。


2.6 类属性与实例属性

实例属性

每个对象自己拥有。

class User:
    def __init__(self, name):
        self.name = name

类属性

所有对象共享。

class User:
    species = "human"

    def __init__(self, name):
        self.name = name
u1 = User("Tom")
u2 = User("Alice")
print(u1.species)
print(u2.species)

区别

  • 实例属性:每个对象不同
  • 类属性:多个对象共享

2.7 面向对象三大基础认知

封装

把数据和操作数据的方法放在一起。

继承

子类复用父类能力。

多态

同样的方法名,在不同对象上有不同实现。

现阶段重点掌握:

  • 对象
  • self
  • 属性与方法

2.8 简单继承

class Animal:
    def speak(self):
        return "..."

class Dog(Animal):
    def speak(self):
        return "wang"

子类可以:

  • 继承父类方法
  • 重写父类方法

2.9 难点与易错点

self 不能忘

class Student:
    def introduce():
        pass

实例方法里如果少了 self,调用会报错。

self.namename 不要混

class Student:
    def __init__(self, name):
        self.name = name
  • name:参数
  • self.name:对象属性

类更适合“有状态”的对象

例如:

  • 聊天会话管理器
  • 向量检索器
  • 数据库客户端
  • Agent 状态对象

2.10 工程场景

工具类

class PDFLoader:
    def load(self, path):
        ...

服务类

class ChatService:
    def generate(self, messages):
        ...

状态类

class AgentState:
    def __init__(self):
        self.messages = []
        self.tools_used = set()

2.11 必须记住

  • 类是模板,对象是实例
  • __init__ 用于初始化对象
  • self 表示当前对象
  • 属性表示数据,方法表示行为
  • 类适合组织“数据 + 行为 + 状态”

3. 异常处理

3.1 什么是异常

异常是程序运行时出现的错误。

常见异常:

  • ValueError
  • TypeError
  • KeyError
  • IndexError
  • ZeroDivisionError
  • FileNotFoundError

例如:

int("abc")   # ValueError
1 / 0         # ZeroDivisionError

3.2 为什么要处理异常

如果不处理,程序可能直接中断。

异常处理的目的:

  • 防止程序崩溃
  • 给出更清晰的错误信息
  • 做兜底逻辑
  • 提高系统稳定性

后续做 API、RAG、Agent 时都非常关键。


3.3 基本语法

try:
    可能出错的代码
except 某种异常:
    出错后的处理

示例:

try:
    num = int("abc")
except ValueError:
    print("输入不是合法整数")

3.4 捕获多个异常

try:
    ...
except ValueError:
    ...
except TypeError:
    ...

也可以写成:

try:
    ...
except (ValueError, TypeError):
    ...

3.5 except Exception as e

try:
    ...
except Exception as e:
    print(e)

用途:

  • 兜底捕获未知异常

注意:

  • 不要一上来所有地方都只写 except Exception
  • 优先捕获明确异常,最后再做总兜底

3.6 elsefinally

try:
    x = int("123")
except ValueError:
    print("转换失败")
else:
    print("转换成功")
finally:
    print("一定会执行")

含义

  • else:没有异常时执行
  • finally:无论是否异常都会执行

典型用途:

  • 关闭文件
  • 释放资源
  • 清理连接

3.7 主动抛出异常

def divide(a, b):
    if b == 0:
        raise ValueError("除数不能为 0")
    return a / b

作用:

  • 提前阻止非法输入
  • 明确告诉调用方错误原因

3.8 难点与易错点

不要裸 except

错误写法:

try:
    ...
except:
    ...

问题:

  • 把所有异常都吞掉
  • 不利于定位问题

不要把异常处理当“隐藏错误”

应该:

  • 记录异常原因
  • 返回清晰错误信息
  • 适当兜底

区分“能恢复”和“不能恢复”的错误

  • 可恢复:输入格式错、文件不存在、网络超时
  • 不可恢复:核心逻辑严重错误

3.9 工程场景

接口参数解析

try:
    age = int(user_input)
except ValueError:
    return {"error": "年龄必须是整数"}

文件读取

try:
    with open("a.txt", "r", encoding="utf-8") as f:
        content = f.read()
except FileNotFoundError:
    print("文件不存在")

调用外部服务

  • 网络请求失败
  • 模型调用超时
  • 数据库连接异常

这些都要有异常兜底。


3.10 必须记住

  • 异常是运行时错误
  • try-except 用于捕获异常
  • finally 常用于资源释放
  • raise 用于主动抛出异常
  • 异常处理的目标是:稳定 + 清晰 + 可排查

4. 文件与 JSON

4.1 文件操作基础

打开文件

f = open("a.txt", "r", encoding="utf-8")

常见模式

  • r:读
  • w:写,覆盖原内容
  • a:追加
  • b:二进制

4.2 推荐写法:with

with open("a.txt", "r", encoding="utf-8") as f:
    content = f.read()

好处:

  • 自动关闭文件
  • 更安全
  • 更符合工程习惯

4.3 读取文件

一次性读全部内容

with open("a.txt", "r", encoding="utf-8") as f:
    content = f.read()

按行读取

with open("a.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()

或:

with open("a.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line)

4.4 写入文件

with open("a.txt", "w", encoding="utf-8") as f:
    f.write("hello")

追加:

with open("a.txt", "a", encoding="utf-8") as f:
    f.write("\nworld")

4.5 JSON 是什么

JSON 是后端和 AI 应用中最常见的数据交换格式。

典型特征:

  • 对象:键值对
  • 数组:列表
  • 文本格式
  • 跨语言通用

例如:

{
  "name": "Tom",
  "age": 20,
  "skills": ["Python", "FastAPI"]
}

Python 中通常对应:

data = {
    "name": "Tom",
    "age": 20,
    "skills": ["Python", "FastAPI"]
}

4.6 Python 读写 JSON

需要 json 模块。

JSON 字符串 -> Python 对象

import json

text = '{"name": "Tom", "age": 20}'
data = json.loads(text)

Python 对象 -> JSON 字符串

import json

data = {"name": "Tom", "age": 20}
text = json.dumps(data, ensure_ascii=False)

4.7 JSON 文件读写

读取 JSON 文件

import json

with open("data.json", "r", encoding="utf-8") as f:
    data = json.load(f)

写入 JSON 文件

import json

data = {"name": "Tom", "age": 20}

with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

4.8 load/loadsdump/dumps 区别

读取

  • json.load(f):从文件对象读取 JSON
  • json.loads(text):从字符串读取 JSON

写入

  • json.dump(data, f):写入文件
  • json.dumps(data):转成 JSON 字符串

这是高频易混点。


4.9 难点与易错点

JSON 的 key 必须是字符串

虽然 Python dict 更灵活,但 JSON 对象的 key 通常是字符串。

Python 的单引号不是标准 JSON

Python dict:

{'name': 'Tom'}

标准 JSON:

{"name": "Tom"}

注意编码

读写中文文件或 JSON 时,常用:

encoding="utf-8"

文件模式要选对

  • w 会覆盖原内容
  • a 才是追加

4.10 工程场景

配置文件

config = json.load(f)

保存模型返回结果

json.dump(result, f, ensure_ascii=False, indent=2)

接口请求 / 响应

FastAPI、前后端交互、模型调用都大量使用 JSON。

RAG 中的元数据缓存

文档块、索引信息、评测结果都可能落成 JSON。


4.11 必须记住

  • 文件操作优先用 with open(...)
  • r / w / a 要分清
  • JSON 是最常用的数据交换格式
  • load/loads 是读取
  • dump/dumps 是写出
  • JSON 和 Python 的 dict + list 高度对应

5. 模块化与 typing

5.1 什么是模块化

模块化就是把代码拆分成多个文件、多个模块,让结构更清晰。

例如:

  • main.py
  • utils.py
  • db.py
  • service.py
  • config.py

好处:

  • 降低复杂度
  • 方便维护
  • 方便复用
  • 方便多人协作

5.2 模块与导入

导入整个模块

import math
print(math.sqrt(16))

导入模块中的某个对象

from math import sqrt
print(sqrt(16))

起别名

import numpy as np
from math import sqrt as s

5.3 为什么要模块化

如果所有代码都写在一个文件里:

  • 很难找
  • 很难维护
  • 很难测试
  • 很难扩展

工程里常见拆法:

  • 路由层
  • 服务层
  • 数据访问层
  • 工具层
  • 配置层

5.4 基本拆分思路

工具函数放到 utils.py

# utils.py
def clean_text(text):
    return text.strip()

主程序中导入使用

from utils import clean_text

5.5 if __name__ == "__main__"

def main():
    print("run")

if __name__ == "__main__":
    main()

作用:

  • 当前文件直接运行时执行
  • 被别的文件 import 时不执行

这是 Python 模块化的重要基础。


5.6 什么是 typing

typing 是类型标注,用来提高代码可读性和可维护性。

它的目标不是改变 Python 的动态类型本质,而是:

  • 让代码更清晰
  • 让 IDE 更好提示
  • 让类型检查工具更好发现问题

5.7 基本类型标注

def add(a: int, b: int) -> int:
    return a + b

含义:

  • aint
  • bint
  • 返回值是 int

5.8 常见类型标注

def greet(name: str) -> str:
    return f"hello {name}"

def is_ok(flag: bool) -> bool:
    return not flag

5.9 容器类型标注

现代 Python 常用:

def process(nums: list[int]) -> list[int]:
    return nums

def build_user() -> dict[str, str]:
    return {"name": "Tom"}

visited: set[str] = set()

如果环境较老,也可能见到:

from typing import List, Dict, Set

5.10 Optional

表示“这个值可能是某种类型,也可能是 None”。

from typing import Optional

def find_user(user_id: int) -> Optional[dict]:
    ...

含义:

  • 返回值可能是 dict
  • 也可能是 None

5.11 Union / |

表示多种可能类型。

def parse_value(x: int | str) -> str:
    return str(x)

老写法:

from typing import Union

def parse_value(x: Union[int, str]) -> str:
    return str(x)

5.12 类型标注的意义

可读性更强

函数输入输出更清晰。

IDE 提示更准确

自动补全、跳转、报错更友好。

更适合工程开发

尤其在:

  • FastAPI
  • 数据处理
  • 多模块项目
  • 团队协作

场景里很有价值。


5.13 难点与易错点

类型标注不是强制运行时检查

def add(a: int, b: int) -> int:
    return a + b

Python 运行时不会自动严格检查类型,类型标注主要服务于:

  • 阅读
  • IDE
  • 静态检查工具

不要为了标注而过度复杂

现阶段重点是:

  • 函数参数
  • 返回值
  • 常见容器

先把这些写清楚就够了。

模块划分不要过细也不要过乱

拆模块的目标是清晰,不是为了拆而拆。


5.14 工程场景

FastAPI

def chat(query: str, top_k: int = 3) -> dict:
    ...

RAG

def retrieve(query: str) -> list[dict]:
    ...

Agent

class AgentState:
    messages: list[dict]
    tools_used: set[str]

这些场景中,模块化和 typing 都会让代码结构更稳。


5.15 必须记住

  • 模块化是为了让代码可维护
  • import / from ... import ... 要会看懂
  • if __name__ == "__main__" 是模块运行入口控制
  • 类型标注提升可读性和工程性
  • 现阶段优先掌握:参数类型、返回值类型、常见容器类型

总结:这 5 块的主线

1. 数据结构

解决:数据如何组织

2. 类与对象

解决:数据和行为如何一起组织

3. 异常处理

解决:出错时如何兜底与保持稳定

4. 文件与 JSON

解决:数据如何落盘、读取、交换

5. 模块化与 typing

解决:代码如何变得更清晰、更适合工程开发


Logo

分享最新、最前沿的AI大模型技术,吸纳国内前几批AI大模型开发者

更多推荐