【设计模式】 Python代理模式:从入门到实战

Python代理模式:给对象找个"经纪人"

前言

还记得上次租房子的经历吗?你不需要直接和房东打交道,而是通过房产中介------他们帮你筛选房源、谈价格、签合同,还能在你和房东之间充当缓冲。明星也是如此,所有商演、代言都通过经纪人,粉丝想见面?先过经纪人这一关。

这就是现实生活中的"代理"。在编程世界里,代理模式扮演着同样的角色:为目标对象提供一个替身或占位符,让客户端不直接访问真实对象,而是通过代理来间接访问。

代理能做什么?控制访问权限、延迟加载昂贵资源、添加缓存层、记录日志、计算性能...简单说,就是在不改变原对象的情况下,给它加上各种"增值服务"。

这篇文章会从最简单的保护代理开始,逐步深入到虚拟代理、缓存代理,最后实现一个完整的数据库查询代理系统------集成连接池、缓存、监控于一体的生产级方案。

一、代理模式是什么?

1. 核心思想

想象一下这个场景:你要访问一个大型图片文件,但加载它需要3秒。如果用户打开页面就立即加载所有图片,页面会卡死。怎么办?

传统做法可能是在图片组件里加一堆if判断:

python 复制代码
if not loaded:
    load_image()
if cache_exists:
    return from_cache()
if not has_permission:
    raise Exception()

这样的代码很快就会变得混乱,而且每个需要这些功能的地方都要重复写一遍。

代理模式提供了更优雅的方案:创建一个代理对象,它和真实对象有相同的接口,但在调用真实对象前后可以加入额外的逻辑。

2. 基本结构

复制代码
客户端 → 代理对象 → 真实对象
          ↓
       额外功能
     (权限、缓存、日志...)

代理和真实对象实现相同的接口,客户端只知道接口,不知道自己用的是代理还是真实对象。

3. 代理的类型

代理模式有很多变体,常见的包括:

类型 用途 典型场景
虚拟代理 延迟创建昂贵对象 图片懒加载、数据库连接池
保护代理 控制访问权限 用户权限验证、敏感数据访问
远程代理 隐藏对象在不同地址空间 RPC调用、分布式对象
缓存代理 缓存结果,减少重复计算 API请求缓存、查询缓存
智能引用 添加额外操作 引用计数、日志记录

本文会重点讲解前四种最常用的代理类型。

二、保护代理:访问控制的门卫

1. 场景描述

假设我们有一个文档系统,不同角色的用户有不同权限:

  • 普通用户:只能查看文档
  • 编辑者:可以查看和编辑文档
  • 管理员:可以查看、编辑和删除文档

如果在文档类里写一堆权限判断,代码会很乱。保护代理可以帮我们优雅地解决这个问题。

2. 代码实现

首先定义接口和真实对象:

python 复制代码
from abc import ABC, abstractmethod
from enum import Enum
from typing import Optional


class Role(Enum):
    """用户角色"""
    VIEWER = "viewer"      # 查看者
    EDITOR = "editor"      # 编辑者
    ADMIN = "admin"        # 管理员


class Document(ABC):
    """文档接口"""

    @abstractmethod
    def view(self) -> str:
        pass

    @abstractmethod
    def edit(self, content: str) -> None:
        pass

    @abstractmethod
    def delete(self) -> None:
        pass


class RealDocument(Document):
    """真实文档"""

    def __init__(self, title: str, content: str):
        self.title = title
        self.content = content
        self.deleted = False

    def view(self) -> str:
        if self.deleted:
            return "[文档已删除]"
        return f"《{self.title}》\n{self.content}"

    def edit(self, content: str) -> None:
        if self.deleted:
            print("[错误] 无法编辑已删除的文档")
            return
        old_content = self.content
        self.content = content
        print(f"[编辑] 文档已更新")
        print(f"  旧内容: {old_content[:20]}...")
        print(f"  新内容: {content[:20]}...")

    def delete(self) -> None:
        if self.deleted:
            print("[错误] 文档已被删除")
            return
        self.deleted = True
        print(f"[删除] 文档《{self.title}》已删除")

然后创建保护代理:

python 复制代码
class DocumentProxy(Document):
    """文档保护代理 - 控制访问权限"""

    def __init__(self, real_document: RealDocument, user_role: Role):
        self._real_document = real_document
        self._user_role = user_role

    def view(self) -> str:
        # 所有角色都可以查看
        print(f"[权限检查] {self._user_role.value} 正在查看文档")
        return self._real_document.view()

    def edit(self, content: str) -> None:
        # 只有编辑者和管理员可以编辑
        if self._user_role in [Role.EDITOR, Role.ADMIN]:
            print(f"[权限检查] {self._user_role.value} 有编辑权限")
            self._real_document.edit(content)
        else:
            print(f"[权限拒绝] {self._user_role.value} 无编辑权限")

    def delete(self) -> None:
        # 只有管理员可以删除
        if self._user_role == Role.ADMIN:
            print(f"[权限检查] {self._user_role.value} 有删除权限")
            self._real_document.delete()
        else:
            print(f"[权限拒绝] {self._user_role.value} 无删除权限")

3. 使用示例

python 复制代码
def main():
    # 创建真实文档
    doc = RealDocument(
        title="Python设计模式",
        content="代理模式是一种结构型设计模式..."
    )

    print("=" * 50)
    print("场景1: 普通用户")
    print("=" * 50)
    viewer_proxy = DocumentProxy(doc, Role.VIEWER)
    print(viewer_proxy.view())
    viewer_proxy.edit("尝试修改内容")  # 被拒绝
    viewer_proxy.delete()  # 被拒绝

    print("\n" + "=" * 50)
    print("场景2: 编辑者")
    print("=" * 50)
    editor_proxy = DocumentProxy(doc, Role.EDITOR)
    print(editor_proxy.view())
    editor_proxy.edit("编辑者修改了内容")  # 成功
    editor_proxy.delete()  # 被拒绝

    print("\n" + "=" * 50)
    print("场景3: 管理员")
    print("=" * 50)
    admin_proxy = DocumentProxy(doc, Role.ADMIN)
    print(admin_proxy.view())
    admin_proxy.edit("管理员修改了内容")  # 成功
    admin_proxy.delete()  # 成功
    print(admin_proxy.view())  # 已删除


if __name__ == "__main__":
    main()

4. 运行效果

复制代码
==================================================
场景1: 普通用户
==================================================
[权限检查] viewer 正在查看文档
《Python设计模式》
代理模式是一种结构型设计模式...
[权限拒绝] viewer 无编辑权限
[权限拒绝] viewer 无删除权限

==================================================
场景2: 编辑者
==================================================
[权限检查] editor 正在查看文档
《Python设计模式》
编辑者修改了内容
[权限检查] editor 有编辑权限
[编辑] 文档已更新
  旧内容: 代理模式是一种结构型设计模式...
  新内容: 编辑者修改了内容...
[权限拒绝] editor 无删除权限

==================================================
场景3: 管理员
==================================================
[权限检查] admin 正在查看文档
《Python设计模式》
编辑者修改了内容
[权限检查] admin 有编辑权限
[编辑] 文档已更新
  旧内容: 编辑者修改了内容...
  新内容: 管理员修改了内容...
[权限检查] admin 有删除权限
[删除] 文档《Python设计模式》已删除
[权限检查] admin 正在查看文档
[文档已删除]

优势

  1. 权限逻辑和业务逻辑分离
  2. 真实文档类保持简洁,不需要关心权限
  3. 可以轻松添加新的权限级别
  4. 代理可以随意组合(可以再套一层日志代理)

三、虚拟代理:延迟加载大对象

1. 场景描述

假设你在开发一个图片浏览器,每张图片有10MB,如果一次性加载100张图片,内存会爆炸。解决方案:只在用户真正查看图片时才加载。

这就是虚拟代理的用武之地。

2. 代码实现

python 复制代码
import time
from abc import ABC, abstractmethod
from typing import Optional


class Image(ABC):
    """图片接口"""

    @abstractmethod
    def display(self) -> None:
        pass

    @abstractmethod
    def get_info(self) -> str:
        pass


class RealImage(Image):
    """真实图片 - 加载很慢"""

    def __init__(self, filename: str):
        self.filename = filename
        self._load_from_disk()

    def _load_from_disk(self) -> None:
        """模拟从磁盘加载图片(耗时操作)"""
        print(f"[加载中] 正在从磁盘加载 {self.filename}...")
        time.sleep(1)  # 模拟耗时操作
        print(f"[完成] {self.filename} 加载完成(占用10MB内存)")
        self.data = f"<{self.filename}的图像数据>"

    def display(self) -> None:
        print(f"[显示] {self.filename}")
        print(f"  数据: {self.data}")

    def get_info(self) -> str:
        return f"{self.filename} (已加载)"


class ImageProxy(Image):
    """图片虚拟代理 - 延迟加载"""

    def __init__(self, filename: str):
        self.filename = filename
        self._real_image: Optional[RealImage] = None

    def display(self) -> None:
        """只在真正显示时才加载图片"""
        if self._real_image is None:
            print(f"[代理] 首次显示,开始加载...")
            self._real_image = RealImage(self.filename)
        else:
            print(f"[代理] 使用已加载的图片")

        self._real_image.display()

    def get_info(self) -> str:
        """获取信息不需要加载图片"""
        if self._real_image is None:
            return f"{self.filename} (未加载)"
        return self._real_image.get_info()


def main():
    print("=" * 60)
    print("不使用代理:创建时立即加载")
    print("=" * 60)
    start = time.time()
    images = [
        RealImage("photo1.jpg"),
        RealImage("photo2.jpg"),
        RealImage("photo3.jpg"),
    ]
    print(f"\n[统计] 创建3张图片耗时: {time.time() - start:.2f}秒\n")

    print("=" * 60)
    print("使用代理:创建时不加载,显示时才加载")
    print("=" * 60)
    start = time.time()
    proxy_images = [
        ImageProxy("photo4.jpg"),
        ImageProxy("photo5.jpg"),
        ImageProxy("photo6.jpg"),
    ]
    print(f"\n[统计] 创建3个代理耗时: {time.time() - start:.2f}秒")
    print("[说明] 代理创建几乎不耗时!\n")

    # 查看图片信息(不触发加载)
    print("查看图片列表(不加载图片):")
    for proxy in proxy_images:
        print(f"  - {proxy.get_info()}")

    # 只显示用户选择的图片
    print("\n用户点击了第2张图片:")
    proxy_images[1].display()

    print("\n用户再次点击第2张图片:")
    proxy_images[1].display()

    print("\n用户点击了第3张图片:")
    proxy_images[2].display()


if __name__ == "__main__":
    main()

3. 运行效果

复制代码
============================================================
不使用代理:创建时立即加载
============================================================
[加载中] 正在从磁盘加载 photo1.jpg...
[完成] photo1.jpg 加载完成(占用10MB内存)
[加载中] 正在从磁盘加载 photo2.jpg...
[完成] photo2.jpg 加载完成(占用10MB内存)
[加载中] 正在从磁盘加载 photo3.jpg...
[完成] photo3.jpg 加载完成(占用10MB内存)

[统计] 创建3张图片耗时: 3.01秒

============================================================
使用代理:创建时不加载,显示时才加载
============================================================

[统计] 创建3个代理耗时: 0.00秒
[说明] 代理创建几乎不耗时!

查看图片列表(不加载图片):
  - photo4.jpg (未加载)
  - photo5.jpg (未加载)
  - photo6.jpg (未加载)

用户点击了第2张图片:
[代理] 首次显示,开始加载...
[加载中] 正在从磁盘加载 photo5.jpg...
[完成] photo5.jpg 加载完成(占用10MB内存)
[显示] photo5.jpg
  数据: <photo5.jpg的图像数据>

用户再次点击第2张图片:
[代理] 使用已加载的图片
[显示] photo5.jpg
  数据: <photo5.jpg的图像数据>

用户点击了第3张图片:
[代理] 首次显示,开始加载...
[加载中] 正在从磁盘加载 photo6.jpg...
[完成] photo6.jpg 加载完成(占用10MB内存)
[显示] photo6.jpg
  数据: <photo6.jpg的图像数据>

效果对比

  • 不使用代理:创建3张图片需要3秒,占用30MB内存
  • 使用代理:创建瞬间完成,只在需要时加载,节省内存和时间

四、缓存代理:让API飞起来

1. 场景描述

你在调用第三方天气API,每次请求需要500ms,而且有请求次数限制。用户频繁刷新页面会导致:

  1. 响应慢
  2. 超过API调用限制
  3. 浪费带宽

缓存代理可以完美解决这个问题。

2. 代码实现

python 复制代码
import time
from abc import ABC, abstractmethod
from typing import Dict, Optional
from datetime import datetime, timedelta


class WeatherAPI(ABC):
    """天气API接口"""

    @abstractmethod
    def get_weather(self, city: str) -> Dict:
        pass


class RealWeatherAPI(WeatherAPI):
    """真实天气API - 调用很慢"""

    def __init__(self):
        self.request_count = 0

    def get_weather(self, city: str) -> Dict:
        """模拟API调用"""
        self.request_count += 1
        print(f"[API调用] 正在请求 {city} 的天气数据...")
        print(f"[统计] 这是第 {self.request_count} 次API调用")

        # 模拟网络延迟
        time.sleep(0.5)

        # 模拟API响应
        return {
            "city": city,
            "temperature": 25,
            "weather": "晴天",
            "humidity": "60%",
            "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        }


class WeatherAPIProxy(WeatherAPI):
    """天气API缓存代理"""

    def __init__(self, real_api: RealWeatherAPI, cache_duration: int = 300):
        """
        Args:
            real_api: 真实API对象
            cache_duration: 缓存有效期(秒),默认5分钟
        """
        self._real_api = real_api
        self._cache: Dict[str, Dict] = {}
        self._cache_time: Dict[str, datetime] = {}
        self._cache_duration = timedelta(seconds=cache_duration)

    def get_weather(self, city: str) -> Dict:
        """获取天气,优先使用缓存"""
        now = datetime.now()

        # 检查缓存是否存在且未过期
        if city in self._cache:
            cache_time = self._cache_time[city]
            if now - cache_time < self._cache_duration:
                age = (now - cache_time).seconds
                print(f"[缓存命中] 返回 {city} 的缓存数据({age}秒前)")
                return self._cache[city]
            else:
                print(f"[缓存过期] {city} 的缓存已过期,重新请求")
        else:
            print(f"[缓存未命中] {city} 无缓存,首次请求")

        # 缓存不存在或已过期,调用真实API
        result = self._real_api.get_weather(city)

        # 更新缓存
        self._cache[city] = result
        self._cache_time[city] = now
        print(f"[缓存更新] {city} 的数据已缓存")

        return result

    def clear_cache(self, city: Optional[str] = None) -> None:
        """清除缓存"""
        if city:
            if city in self._cache:
                del self._cache[city]
                del self._cache_time[city]
                print(f"[缓存清除] 已清除 {city} 的缓存")
        else:
            self._cache.clear()
            self._cache_time.clear()
            print("[缓存清除] 已清除所有缓存")

    def get_cache_stats(self) -> Dict:
        """获取缓存统计"""
        return {
            "cached_cities": list(self._cache.keys()),
            "cache_size": len(self._cache),
            "total_requests": self._real_api.request_count
        }


def main():
    # 创建真实API和代理
    real_api = RealWeatherAPI()
    proxy = WeatherAPIProxy(real_api, cache_duration=10)  # 10秒缓存

    print("=" * 60)
    print("测试缓存代理")
    print("=" * 60)

    # 第一次请求北京天气
    print("\n【第1次】查询北京天气:")
    start = time.time()
    weather = proxy.get_weather("北京")
    print(f"  结果: {weather['weather']}, {weather['temperature']}°C")
    print(f"  耗时: {time.time() - start:.2f}秒\n")

    # 第二次请求北京天气(应该命中缓存)
    print("【第2次】查询北京天气(1秒后):")
    time.sleep(1)
    start = time.time()
    weather = proxy.get_weather("北京")
    print(f"  结果: {weather['weather']}, {weather['temperature']}°C")
    print(f"  耗时: {time.time() - start:.2f}秒\n")

    # 查询其他城市
    print("【第3次】查询上海天气:")
    start = time.time()
    weather = proxy.get_weather("上海")
    print(f"  结果: {weather['weather']}, {weather['temperature']}°C")
    print(f"  耗时: {time.time() - start:.2f}秒\n")

    # 再次查询北京(还在缓存期内)
    print("【第4次】查询北京天气(3秒后):")
    time.sleep(2)
    start = time.time()
    weather = proxy.get_weather("北京")
    print(f"  结果: {weather['weather']}, {weather['temperature']}°C")
    print(f"  耗时: {time.time() - start:.2f}秒\n")

    # 显示缓存统计
    print("=" * 60)
    stats = proxy.get_cache_stats()
    print(f"缓存统计:")
    print(f"  已缓存城市: {stats['cached_cities']}")
    print(f"  缓存数量: {stats['cache_size']}")
    print(f"  API调用总数: {stats['total_requests']} 次")
    print(f"  缓存节省: {4 - stats['total_requests']} 次API调用")


if __name__ == "__main__":
    main()

3. 运行效果

复制代码
============================================================
测试缓存代理
============================================================

【第1次】查询北京天气:
[缓存未命中] 北京 无缓存,首次请求
[API调用] 正在请求 北京 的天气数据...
[统计] 这是第 1 次API调用
[缓存更新] 北京 的数据已缓存
  结果: 晴天, 25°C
  耗时: 0.50秒

【第2次】查询北京天气(1秒后):
[缓存命中] 返回 北京 的缓存数据(1秒前)
  结果: 晴天, 25°C
  耗时: 0.00秒

【第3次】查询上海天气:
[缓存未命中] 上海 无缓存,首次请求
[API调用] 正在请求 上海 的天气数据...
[统计] 这是第 2 次API调用
[缓存更新] 上海 的数据已缓存
  结果: 晴天, 25°C
  耗时: 0.50秒

【第4次】查询北京天气(3秒后):
[缓存命中] 返回 北京 的缓存数据(3秒前)
  结果: 晴天, 25°C
  耗时: 0.00秒

============================================================
缓存统计:
  已缓存城市: ['北京', '上海']
  缓存数量: 2
  API调用总数: 2 次
  缓存节省: 2 次API调用

性能对比

  • 无缓存:4次查询 = 4次API调用 = 2秒
  • 有缓存:4次查询 = 2次API调用 = 1秒,节省50%时间和请求

五、完整实战:数据库查询代理系统

现在我们来实现一个生产级的数据库代理系统,整合:

  1. 连接池管理:避免频繁创建连接
  2. 查询缓存:减少数据库压力
  3. 性能监控:记录查询耗时
  4. 错误重试:自动重试失败的查询

这个系统会是一个完整的FastAPI应用,可以直接部署使用。

1. 项目结构

复制代码
db_proxy/
├── main.py                    # FastAPI主应用
├── proxies/                   # 代理层
│   ├── __init__.py
│   ├── base.py                # 代理基类
│   └── db_proxy.py            # 数据库代理
├── database/                  # 数据库层
│   ├── __init__.py
│   ├── connection.py          # 数据库连接
│   └── models.py              # 数据模型
└── services/                  # 业务服务
    ├── __init__.py
    └── user_service.py        # 用户服务

2. 核心代码

代理基类和数据库连接在后面的代码文件中实现,这里展示FastAPI主应用如何使用:

监控效果示例

python 复制代码
# 查询会被自动缓存和监控
GET /users?role=admin

# 响应包含性能数据
{
    "data": [...],
    "cache_hit": true,
    "query_time": 0.001,
    "from_cache": true
}

优势总结

  1. 透明性:业务代码不知道代理的存在
  2. 可组合:可以叠加多个代理(缓存→日志→连接池)
  3. 易测试 :可以用Mock代理替换真实数据库
  4. 高性能:缓存大幅减少数据库压力

六、代理模式 vs 相似模式

代理模式经常和其他模式混淆,这里做个对比:

特性 代理模式 适配器模式 装饰器模式
目的 控制访问、延迟加载、缓存 接口转换 动态添加功能
接口 与真实对象相同 转换不兼容的接口 与原对象相同
对象创建 代理可以控制对象的创建 适配已存在的对象 装饰已存在的对象
典型场景 权限控制、虚拟代理、缓存 第三方API对接 日志、事务、性能统计
关系 代理控制真实对象 适配器转换接口 装饰器增强功能

举例说明

  • 代理:房产中介(控制你和房东的接触)
  • 适配器:电源转换器(转换电压接口)
  • 装饰器:给手机贴膜(增加保护功能)

何时用代理

  • 需要控制对象访问
  • 对象创建成本高,需要延迟加载
  • 需要在不修改原代码的情况下添加缓存
  • 需要记录对象的使用情况

何时不用代理

  • 只是简单调用,不需要额外控制
  • 接口不兼容(用适配器)
  • 要动态叠加多个功能(用装饰器)

七、最佳实践

1. 代理应该对客户端透明

python 复制代码
# ✅ 好的做法:客户端不知道代理的存在
def get_user_service() -> UserRepository:
    real_repo = DatabaseRepository()
    return CacheProxy(real_repo)  # 返回代理

service = get_user_service()
user = service.get_user(1)  # 客户端不知道用的是代理

# ❌ 不好的做法:客户端需要知道代理
proxy = CacheProxy(DatabaseRepository())
if use_cache:
    user = proxy.get_user(1)
else:
    user = proxy._real_repo.get_user(1)  # 直接访问真实对象

2. 代理可以组合使用

python 复制代码
# 多层代理:缓存 → 日志 → 真实对象
real_api = WeatherAPI()
logged_api = LoggingProxy(real_api)
cached_api = CacheProxy(logged_api)

# 请求会经过:CacheProxy → LoggingProxy → WeatherAPI
weather = cached_api.get_weather("北京")

3. 虚拟代理要考虑线程安全

python 复制代码
class ThreadSafeImageProxy(Image):
    def __init__(self, filename: str):
        self.filename = filename
        self._real_image: Optional[RealImage] = None
        self._lock = threading.Lock()

    def display(self) -> None:
        if self._real_image is None:
            with self._lock:  # 双重检查锁定
                if self._real_image is None:
                    self._real_image = RealImage(self.filename)
        self._real_image.display()

4. 缓存代理要设置合理的过期策略

python 复制代码
class SmartCacheProxy:
    def __init__(self):
        self._cache = {}
        self._access_count = {}  # 访问计数
        self._max_size = 100     # 最大缓存数

    def get(self, key):
        if key in self._cache:
            self._access_count[key] += 1
            return self._cache[key]

        # 缓存满了,淘汰最少使用的
        if len(self._cache) >= self._max_size:
            least_used = min(self._access_count, key=self._access_count.get)
            del self._cache[least_used]
            del self._access_count[least_used]

        # 从真实对象获取
        result = self._real_object.get(key)
        self._cache[key] = result
        self._access_count[key] = 1
        return result

八、总结

代理模式就像现实中的经纪人,为对象提供"增值服务":

核心价值

  1. 访问控制:保护代理控制谁能访问对象
  2. 延迟初始化:虚拟代理避免昂贵对象的提前创建
  3. 性能优化:缓存代理减少重复计算和网络请求
  4. 附加功能:不修改原对象就能添加日志、监控等

适用场景

  • 对象创建成本高(大文件、数据库连接)
  • 需要权限控制(敏感数据访问)
  • 需要缓存结果(API调用、复杂查询)
  • 需要记录使用情况(日志、性能监控)

实现要点

  • 代理和真实对象实现相同接口
  • 代理持有真实对象的引用
  • 代理可以在调用前后添加额外逻辑
  • 对客户端透明,客户端不知道使用的是代理

下次当你需要在不修改原有代码的情况下,为对象添加访问控制、延迟加载或缓存功能时,想想代理模式------给你的对象找个"经纪人",让它更专业、更高效!


如果这篇文章对你有帮助,请给我三连支持:

  1. 点赞 👍 - 让更多人看到这篇文章
  2. 收藏 ⭐ - 方便以后查阅
  3. 分享 📤 - 帮助更多需要的人

你的支持是我创作的最大动力!

也欢迎在评论区分享你使用代理模式的经验,或者提出你的疑问,我会认真回复每一条评论。

作者:山沐与山

本文版权归作者所有,欢迎转载,但请注明出处。

相关推荐
言之。2 小时前
Python调用DeepSeek API查询ClickHouse
windows·python·clickhouse
SCBAiotAigc2 小时前
Chrome的cookie编辑插件EditThisCookie
人工智能·chrome·python·ubuntu
范纹杉想快点毕业2 小时前
C语言设计模式:从基础架构到高级并发系统(完整实现版)
c语言·开发语言·设计模式
dagouaofei2 小时前
运营述职 PPT 工具横评:效率与呈现谁更优
python·powerpoint
先做个垃圾出来………2 小时前
Python测试桩工具
java·开发语言·python
小芳矶2 小时前
【langchain框架——检索链】利用检索链创建自己的购物知识库并完成智能体的商品推荐
java·python·langchain
就叫飞六吧2 小时前
py脚本一键生成常见文件格式案例
开发语言·python
AI能力探索2 小时前
Python机器学习三大经典算法:KNN、SVM、朴素贝叶斯
python
盼哥PyAI实验室3 小时前
Python 爬虫实战:从 Ajax 到 POST 请求,完整爬取汉堡王门店与产品数据
爬虫·python·ajax