Python项目实战——面向对象高级、Web 开发

一、面向对象高级:封装、继承与多态

面向对象编程(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,子类GasCarElectricCarHybridCar,各自重写startrun方法。

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中定义的接口(startrun),但实际调用时,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 快速起步

步骤:

  1. 导入FastAPI并创建实例

  2. 定义路径操作函数(装饰器 + 函数)

  3. 运行服务

from fastapi import FastAPI app = FastAPI() @app.get("/") def read_root(): return {"message": "Hello World"} # 启动方式1:fastapi dev main.py # 启动方式2:uvicorn main:app --reload
  • fastapi 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 基础环境搭建

  1. 将前端静态文件(HTML/CSS/JS)放入static/目录

  2. 在 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": "你好"}

  • 核心流程

    1. 根据session_id加载 JSON 文件中的消息列表

    2. 将用户消息追加到列表

    3. 调用 DeepSeek API(带上完整的历史消息),获取 AI 回复

    4. 将 AI 回复也追加到列表

    5. 将更新后的列表写回 JSON 文件

    6. 返回 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 服务。希望你能动手敲一遍代码,真正将知识内化为能力。如果遇到问题,欢迎在评论区交流探讨!