一、面向对象高级:封装、继承与多态
面向对象编程(OOP)是 Python 的基石,也是构建可维护、可扩展 Web 项目的必备武器。本章我们将深入三大特性——封装、继承、多态,并通过一个图书管理系统的案例将它们串起来。
1.1 封装 —— 把数据与行为关进“黑盒”
1.1.1 什么是封装?
封装就是把数据(属性)和操作数据的函数(方法)捆绑在一起,形成一个独立的单元(类),并隐藏内部的实现细节,只对外暴露必要的功能(方法)。
简单来说:类 = 属性 + 方法,外部只能通过公共接口与对象交互,内部细节不可见。
1.1.2 私有成员与公共成员
Python 中以__(双下划线)开头的属性和方法会被视为私有,只能在类的内部访问,外部无法直接引用。但这并非真正的强制私有,而是一种“名称修饰”(name mangling),本质上仍可绕过,但约定上不应访问。
| 成员类型 | 命名方式 | 访问范围 |
|---|---|---|
| 公共属性/方法 | 普通名称 | 类内外均可访问 |
| 私有属性/方法 | 以__开头 | 仅类内部可访问 |
class Book: def __init__(self, title, isbn): self.title = title # 公共属性 self.__isbn = isbn # 私有属性 def __check_secret(self): # 私有方法 return "内部校验逻辑" def show_info(self): return f"{self.title} - 校验码: {self.__check_secret()}"1.1.3 私有成员的应用场景
当某些属性或方法不应暴露给调用方(如内部状态、缓存计算、安全校验),就应当将其设为私有,从而降低耦合,保护数据一致性。
在 Python 中,并没有其他语言(如 Java)那种强制性的“私有”机制。你所指的“私有方法”通常有两种情况,它们的调用方式完全不同:
双下划线开头的“真·私有”方法(名称修饰)
如果一个方法以双下划线__开头(且不以双下划线结尾,如__init__),Python 会对它进行名称修饰(Name Mangling),将名字改为_类名__方法名。
在类内部调用:直接使用
self.__方法名(),Python 会自动帮你转换,完全没问题。在类外部调用:不能直接写
实例.__方法名()(会报错AttributeError),必须使用修饰后的完整名称实例._类名__方法名()。
class MyClass: def __private_method(self): print("私有方法被调用") def public_method(self): # 1. 在类内部:直接调用即可 self.__private_method() # 2. 在类外部:强制调用(不推荐) obj = MyClass() # obj.__private_method() # 报错:AttributeError obj._MyClass__private_method() # 输出:私有方法被调用1.2 继承 —— 子承父业,复用又扩展
1.2.1 继承的本质
继承描述的是两个类之间的is-a关系。子类继承父类后,会自动获得父类所有非私有的属性和方法。
class Car: def __init__(self, color, brand, model): self.color = color self.brand = brand self.model = model def start(self): print(f"{self.brand} {self.model} 正在启动...") def run(self): print(f"{self.brand} {self.model} 正在行驶...")子类只需指定父类名即可:
class FuelCar(Car): pass class ElectricCar(Car): pass子类拥有父类全部公共功能,无需重复编写。
1.2.2 方法重写(Override)
当父类的方法不能满足子类需求时,子类可以重新定义同名方法,用自己的逻辑替换父类实现。
class ElectricCar(Car): def start(self): print(f"{self.brand} {self.model} 静音启动(电机)")在子类中调用父类方法有两种方式:
super().方法名()(推荐)父类名.方法名(self)
1.2.3 多继承与 MRO
Python 支持多继承,即一个子类同时继承多个父类,获取所有父类的公共成员。
class A: def method(self): print("A") class B: def method(self): print("B") class C(A, B): pass当多个父类有同名方法时,Python 通过MRO(方法解析顺序)决定调用顺序,可使用类名.__mro__查看。默认优先使用第一个父类中的同名属性或方法
1.3 多态 —— 同一接口,多种形态
1.3.1 什么是多态?
多态是指同一个方法,在不同的对象上表现出不同的行为。在 Python 中,多态通常体现为:函数参数为父类类型,运行时传入不同子类对象,调用同一个方法产生不同效果。
def drive(car: Car): car.start() car.run()定义父类Car,子类GasCar、ElectricCar、HybridCar,各自重写start和run方法。
class Car: """父类(抽象基类,定义接口)""" def start(self): raise NotImplementedError("子类必须实现 start()") def run(self): raise NotImplementedError("子类必须实现 run()") class GasCar(Car): def start(self): print("🔑 拧动钥匙,点燃汽油发动机") def run(self): print("⛽ 汽油车行驶,排放尾气") class ElectricCar(Car): def start(self): print("⚡ 按下启动按钮,接通电池供电") def run(self): print("🔋 电动车安静行驶,零排放") class HybridCar(Car): def start(self): print("🌱 智能切换:低速用电,高速用油") def run(self): print("🔄 混动车根据路况自动分配动力") # 多态函数:接受任何 Car 的子类实例 def drive(car: Car): car.start() car.run() print("-" * 30) # 测试多态 if __name__ == "__main__": cars = [GasCar(), ElectricCar(), HybridCar()] for c in cars: drive(c)运行结果:
🔑 拧动钥匙,点燃汽油发动机 ⛽ 汽油车行驶,排放尾气 ------------------------------ ⚡ 按下启动按钮,接通电池供电 🔋 电动车安静行驶,零排放 ------------------------------ 🌱 智能切换:低速用电,高速用油 🔄 混动车根据路况自动分配动力 ------------------------------解析:drive函数只依赖Car中定义的接口(start和run),但实际调用时,Python 会根据传入对象的真实类型(子类)动态绑定到对应的重写方法,从而产生不同的行为。这就是多态。
1.3.2 鸭子类型(Duck Typing)
Python 更崇尚鸭子类型:“如果它走起路来像鸭子,叫起来像鸭子,那它就是鸭子。” 我们关注对象有没有某个方法,而不关心它是否继承自某个父类。
# ---------- 原有的汽车族(继承自 Car) ---------- class Car: def start(self): raise NotImplementedError def run(self): raise NotImplementedError class GasCar(Car): def start(self): print("🔑 拧动钥匙,点燃汽油发动机") def run(self): print("⛽ 汽油车行驶,排放尾气") class ElectricCar(Car): def start(self): print("⚡ 按下启动按钮,接通电池供电") def run(self): print("🔋 电动车安静行驶") # ---------- 新增:与 Car 毫无继承关系的类(鸭子类型) ---------- class Airplane: """飞机没有继承 Car,但有 start 和 run 方法""" def start(self): print("🛫 启动涡轮发动机,松开刹车") def run(self): print("✈️ 飞机在跑道高速滑行,随后拉升起飞") class Boat: """船也没有继承 Car,但同样有 start 和 run 方法""" def start(self): print("⛵ 放下锚链,启动船用柴油机") def run(self): print("🚤 船在水面破浪前行") # ---------- 多态函数(鸭子类型版本) ---------- # 注意:这里我去掉了类型注解(或改为 object), # 表示我们不关心传入的是什么类型,只关心它有没有 start 和 run def drive(vehicle): """只要你有 start() 和 run(),我就能带你走""" vehicle.start() vehicle.run() print("-" * 30) # ---------- 测试 ---------- if __name__ == "__main__": # 传入继承体系内的子类(经典多态) drive(GasCar()) drive(ElectricCar()) # 传入完全不相关的类(鸭子类型) drive(Airplane()) drive(Boat())运行结果:
🔑 拧动钥匙,点燃汽油发动机 ⛽ 汽油车行驶,排放尾气 ------------------------------ ⚡ 按下启动按钮,接通电池供电 🔋 电动车安静行驶 ------------------------------ 🛫 启动涡轮发动机,松开刹车 ✈️ 飞机在跑道高速滑行,随后拉升起飞 ------------------------------ ⛵ 放下锚链,启动船用柴油机 🚤 船在水面破浪前行 ------------------------------1.4 抽象类
在 Python 中,抽象类是一种不能被直接实例化的类,它专门用来作为“模板”或“基类”,为其子类定义统一的接口(方法签名)。它的核心作用是强制子类必须实现特定的方法,从而实现代码的规范化,并利用多态性。
Python 通过内置的abc模块(Abstract Base Classes)来实现抽象类。下面从基础到进阶,带你全面掌握它。
1.4.1 基础语法与实现
要定义抽象类,需要继承ABC类,并使用@abstractmethod装饰器标记抽象方法。
from abc import ABC, abstractmethod # 1. 定义抽象类 (继承 ABC) class Animal(ABC): # 抽象方法:子类必须实现 @abstractmethod def make_sound(self) -> str: pass # 抽象方法:子类必须实现 @abstractmethod def move(self) -> str: pass # 具体方法:子类可以直接继承使用,无需重写 def sleep(self) -> str: return "Zzz..." # 2. 子类继承抽象类 class Dog(Animal): # 必须实现所有抽象方法,否则实例化时会报错 def make_sound(self) -> str: return "汪汪" def move(self) -> str: return "跑" # 3. 使用 dog = Dog() print(dog.make_sound()) # 输出: 汪汪 print(dog.sleep()) # 输出: Zzz... (直接继承具体方法) # 试图实例化抽象类本身会报错 # animal = Animal() # TypeError: Can't instantiate abstract class Animal📝 一句话总结(记住这句就行)
抽象类就是一个“只给规定,不能自己用”的父类。它逼着子类必须把某些方法写完,否则程序就报错不让你运行。
二、FastAPI 基础 —— 快速构建 Web API
2.1 Web 初识:前端、后端、数据库
一个完整的 Web 网站由三部分构成:
前端:负责界面展示(HTML + CSS + JavaScript)
后端:负责业务逻辑处理(Python/Django/Flask/FastAPI)
数据库:负责数据存储与管理(MySQL/Redis/文件)
前端三剑客:
HTML定义页面结构(内容)
CSS控制样式(外观)
JS实现交互(行为)
2.2 FastAPI 入门
2.2.1 什么是 FastAPI?
FastAPI 是一个现代、高性能的 Python Web 框架,基于 Python 类型提示,自动生成 OpenAPI 文档,支持异步,速度极快(对标 Node.js 和 Go)。
官网:FastAPI - FastAPI - FastAPI 框架
2.2.2 快速起步
步骤:
导入
FastAPI并创建实例定义路径操作函数(装饰器 + 函数)
运行服务
from fastapi import FastAPI app = FastAPI() @app.get("/") def read_root(): return {"message": "Hello World"} # 启动方式1:fastapi dev main.py # 启动方式2:uvicorn main:app --reloadfastapi dev自动重载,适合开发uvicorn是 ASGI 服务器,生产环境常用
2.2.3 接收 JSON 请求体
使用BaseModel定义数据模型,FastAPI 会自动解析请求体 JSON 并校验。
from pydantic import BaseModel class ChatRequest(BaseModel): session_id: str message: str @app.post("/api/chat") def chat(request: ChatRequest): return {"received": request.message}2.2.4另外一种启动方式(推荐)
三、汉字谜盒案例 —— 从零到一的全栈实战
本项目是一个基于 AI 的字谜互动游戏,用户与 DeepSeek 大模型进行猜字挑战,支持多会话管理、历史记录持久化。
3.1 开发规范与 RESTful 风格
3.1.1 什么是 RESTful?
RESTful 是一种 API 设计风格,核心原则:
URL 定义资源(如
/api/sessions)HTTP 方法描述操作(GET 查询、POST 新增、PUT 修改、DELETE 删除)
例如:
GET /api/sessions # 获取会话列表 POST /api/sessions # 新建会话 GET /api/sessions/{id} # 加载指定会话 DELETE /api/sessions/{id} # 删除会话3.1.2 统一响应格式
所有接口返回统一 JSON 结构:
{ "code": 200, "message": "操作成功", "data": { ... } }3.2 基础环境搭建
将前端静态文件(HTML/CSS/JS)放入
static/目录在 FastAPI 中挂载静态文件目录:
from fastapi.staticfiles import StaticFiles app.mount("/static", StaticFiles(directory="static"), name="static")3.定义根路径返回index.html,用户访问即可进入游戏界面。
3.3 核心功能开发(六大接口)
3.3.1 新建会话
路径:
POST /api/sessions逻辑:生成以时间戳命名的会话 ID(如
2026-04-15_12-00-05),在sessions/目录下创建对应的 JSON 文件,初始消息列表为空。返回:
data为会话 ID。
3.3.2 与 AI 交互
路径:
POST /api/chat请求体:
{"session_id": "...", "message": "你好"}核心流程:
根据
session_id加载 JSON 文件中的消息列表将用户消息追加到列表
调用 DeepSeek API(带上完整的历史消息),获取 AI 回复
将 AI 回复也追加到列表
将更新后的列表写回 JSON 文件
返回 AI 回复内容
# 伪代码 def chat(request: ChatRequest): messages = load_session(request.session_id) messages.append({"role": "user", "content": request.message}) ai_response = call_deepseek(messages) messages.append({"role": "assistant", "content": ai_response}) save_session(request.session_id, messages) return {"code": 200, "data": ai_response}3.3.3 会话列表
路径:
GET /api/sessions逻辑:扫描
sessions/目录下所有.json文件名,按时间倒序排序(从文件名解析时间)。返回:文件名列表(不含扩展名)。
3.3.4 加载指定会话
路径:
GET /api/sessions/{session_id}逻辑:读取对应 JSON 文件,返回完整的消息列表。
返回:
{"current_session": id, "messages": [...]}
3.3.5 删除会话
路径:
DELETE /api/sessions/{session_id}逻辑:删除对应的 JSON 文件。
返回:成功消息。
3.4 程序优化(日志与异常处理)
3.4.1 日志记录
原生的print()难以控制级别、时间、输出位置。使用 Python 内置logging模块:
import logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) logger.info("会话创建成功: %s", session_id)可配置输出到文件、控制台,并支持日志分级(DEBUG/INFO/WARNING/ERROR)。
3.4.2 统一异常处理
使用 FastAPI 的@app.exception_handler捕获全局异常,返回统一格式的 JSON,避免暴露内部错误细节。
from fastapi import HTTPException from fastapi.exceptions import RequestValidationError @app.exception_handler(Exception) async def global_exception_handler(request, exc): return JSONResponse( status_code=500, content={"code": 500, "message": "服务器内部异常", "data": None} )同时针对自定义业务异常(如库存不足、借阅超限),可抛出HTTPException并指定状态码,前端根据 code 友好提示。
四、结语
通过本文,我们从面向对象三大特性出发,借助图书管理系统案例巩固了 OOP 设计;然后快速切入 FastAPI 框架,掌握 Web API 的构建方法;最后通过完整的“汉字谜盒”项目,串联了 RESTful 设计、静态文件托管、JSON 持久化、AI 接口调用、日志与异常处理等实战技能。
这套技术栈非常适合个人开发者快速搭建 AI 应用或轻量级 Web 服务。希望你能动手敲一遍代码,真正将知识内化为能力。如果遇到问题,欢迎在评论区交流探讨!