生成器实战:处理大文件、流水线模式与无限序列

文章目录

    • 一、为什么生成器是工程实践的核心工具
    • 二、场景一:大文件处理
      • [2.1 问题背景](#2.1 问题背景)
      • [2.2 基础:逐行生成器](#2.2 基础:逐行生成器)
      • [2.3 分块处理:应对超大行](#2.3 分块处理:应对超大行)
      • [2.4 大文件统计分析:完整实现](#2.4 大文件统计分析:完整实现)
    • 三、场景二:流水线模式
      • [3.1 流水线的本质](#3.1 流水线的本质)
      • [3.2 构建可复用的流水线组件库](#3.2 构建可复用的流水线组件库)
      • [3.3 实战:电商订单处理流水线](#3.3 实战:电商订单处理流水线)
      • [3.4 流水线的调试技巧](#3.4 流水线的调试技巧)
    • 四、场景三:无限序列
      • [4.1 数学序列的惰性表达](#4.1 数学序列的惰性表达)
      • [4.2 操作无限序列的工具函数](#4.2 操作无限序列的工具函数)
      • [4.3 工程实战:实时滑动窗口统计](#4.3 工程实战:实时滑动窗口统计)
      • [4.4 无限序列与 `zip` 的组合技](#4.4 无限序列与 zip 的组合技)
    • 五、性能陷阱与调优策略
      • [5.1 生成器嵌套过深导致的栈溢出](#5.1 生成器嵌套过深导致的栈溢出)
      • [5.2 `list(generator)` 的内存峰值](#5.2 list(generator) 的内存峰值)
      • [5.3 与 `itertools` 的深度配合](#5.3 与 itertools 的深度配合)
    • 六、生成器流水线的架构全景
    • 七、与标准库的协作
      • [7.1 `contextlib.contextmanager`:把生成器变上下文管理器](#7.1 contextlib.contextmanager:把生成器变上下文管理器)
      • [7.2 `typing.Generator` 的完整签名](#7.2 typing.Generator 的完整签名)
    • 八、模块二完结:从迭代器到生成器的完整知识图谱
    • 小结

一、为什么生成器是工程实践的核心工具

Python 进阶 #06 建立了生成器的基本心智模型,#07 剖析了 yield from 与协程通信。本篇着眼于真实工程场景:当数据规模超过内存上限、当处理步骤之间存在依赖关系、当需要表达数学上的无限结构时,生成器提供了哪些具体、可落地的解决方案。

以下三个场景覆盖了生成器在后端工程中 80% 以上的使用场合。


二、场景一:大文件处理

2.1 问题背景

假设生产日志系统每天产生约 5GB 的 access log,格式为:

复制代码
2026-05-10 08:23:11 INFO  GET /api/users 200 45ms
2026-05-10 08:23:12 ERROR POST /api/order 500 1200ms
2026-05-10 08:23:13 WARN  GET /api/health 200 2ms

需要统计每个接口的:请求数、平均响应时间、5xx 错误率。

把 5GB 文件读进内存是不现实的,必须以流式方式处理。

2.2 基础:逐行生成器

python 复制代码
from pathlib import Path
import re
from typing import Iterator

LOG_PATTERN = re.compile(
    r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+"  # 时间戳
    r"(\w+)\s+"                                      # 日志级别
    r"(\w+)\s+"                                      # HTTP方法
    r"(/\S*)\s+"                                     # 路径
    r"(\d{3})\s+"                                    # 状态码
    r"(\d+)ms"                                       # 响应时间
)

def parse_log_lines(filepath: str) -> Iterator[dict]:
    """
    流式解析日志文件,逐行产出结构化记录。
    文件无论多大,内存中同时只有一行。
    """
    path = Path(filepath)
    with path.open("r", encoding="utf-8") as f:
        for lineno, raw_line in enumerate(f, start=1):
            line = raw_line.strip()
            if not line:
                continue
            m = LOG_PATTERN.match(line)
            if m:
                yield {
                    "timestamp": m.group(1),
                    "level":     m.group(2),
                    "method":    m.group(3),
                    "path":      m.group(4),
                    "status":    int(m.group(5)),
                    "latency_ms": int(m.group(6)),
                }
            else:
                # 解析失败的行记录但不中断流
                yield {"_parse_error": True, "line": lineno, "raw": line}

2.3 分块处理:应对超大行

某些日志包含 JSON body,单行可能达到几十 KB。此时逐行读取本身没有问题(Python 的文件迭代器是行缓冲的),但如果需要处理二进制数据或固定大小的网络包,应使用分块读取:

python 复制代码
def read_chunks(filepath: str, chunk_size: int = 65536) -> Iterator[bytes]:
    """以固定大小块读取二进制文件"""
    with open(filepath, "rb") as f:
        while True:
            chunk = f.read(chunk_size)
            if not chunk:
                break
            yield chunk

# 与 iter() 两参数哨兵形式等价(见 #05)
from functools import partial

def read_chunks_v2(filepath: str, chunk_size: int = 65536) -> Iterator[bytes]:
    with open(filepath, "rb") as f:
        yield from iter(partial(f.read, chunk_size), b"")

2.4 大文件统计分析:完整实现

python 复制代码
from collections import defaultdict
from typing import Iterator

def only_parsed(records: Iterator[dict]) -> Iterator[dict]:
    """过滤掉解析失败的行"""
    for r in records:
        if not r.get("_parse_error"):
            yield r

def accumulate_stats(records: Iterator[dict]) -> dict:
    """
    一趟扫描完成所有统计,不把任何中间数据存入大列表。
    stats 字典只存储聚合指标,内存占用与日志行数无关。
    """
    stats = defaultdict(lambda: {
        "count": 0,
        "total_latency": 0,
        "error_5xx": 0,
    })

    total_lines = 0
    for record in records:
        path = record["path"]
        s = stats[path]
        s["count"] += 1
        s["total_latency"] += record["latency_ms"]
        if record["status"] >= 500:
            s["error_5xx"] += 1
        total_lines += 1

    # 计算平均值和错误率
    result = {}
    for path, s in stats.items():
        result[path] = {
            "count": s["count"],
            "avg_latency_ms": round(s["total_latency"] / s["count"], 2),
            "error_rate_5xx": round(s["error_5xx"] / s["count"], 4),
        }

    print(f"共处理 {total_lines} 行日志")
    return result


def analyze_log(filepath: str) -> dict:
    """
    组装生成器流水线,一趟扫描完成分析。
    内存消耗:O(unique_paths),与文件大小无关。
    """
    raw     = parse_log_lines(filepath)
    cleaned = only_parsed(raw)
    return accumulate_stats(cleaned)

一次一行
一次一条
一次一条
📄 5GB 日志文件

(磁盘)
parse_log_lines

逐行解析

产出 dict
only_parsed

过滤解析失败行
accumulate_stats

聚合统计

(单次扫描)
📊 统计结果

(内存 O(接口数))

关键点 :整条流水线中,任何时刻内存里只存在"当前正在处理的那一条记录",以及 stats 这个聚合字典(大小由唯一接口路径数决定,而非日志总行数)。5GB 的文件与 5MB 的文件,内存消耗几乎相同。


三、场景二:流水线模式

3.1 流水线的本质

数据流水线是生成器最优雅的应用场景之一:每个处理步骤都是一个生成器,前一步的输出直接成为下一步的输入,数据以"一条记录"为单位流过整个管道,没有任何中间物化(materialization)。

这与 Unix 的管道哲学完全一致:cat file | grep ERROR | awk '{print $4}' | sort | uniq -c

3.2 构建可复用的流水线组件库

python 复制代码
from typing import Iterator, TypeVar, Callable, Iterable
T = TypeVar("T")
U = TypeVar("U")

# -------- 通用变换组件 --------

def gmap(func: Callable[[T], U], source: Iterable[T]) -> Iterator[U]:
    """惰性 map:对每个元素应用 func"""
    for item in source:
        yield func(item)

def gfilter(predicate: Callable[[T], bool], source: Iterable[T]) -> Iterator[T]:
    """惰性 filter"""
    for item in source:
        if predicate(item):
            yield item

def gtake(n: int, source: Iterable[T]) -> Iterator[T]:
    """取前 n 个元素"""
    for i, item in enumerate(source):
        if i >= n:
            break
        yield item

def gdrop(n: int, source: Iterable[T]) -> Iterator[T]:
    """跳过前 n 个元素"""
    for i, item in enumerate(source):
        if i >= n:
            yield item

def gchunk(size: int, source: Iterable[T]) -> Iterator[list]:
    """将流切分为固定大小的批次"""
    batch = []
    for item in source:
        batch.append(item)
        if len(batch) >= size:
            yield batch
            batch = []
    if batch:
        yield batch

def gflatmap(func: Callable[[T], Iterable[U]], source: Iterable[T]) -> Iterator[U]:
    """对每个元素应用 func,并展平一层结果"""
    for item in source:
        yield from func(item)

def gtee(source: Iterable[T], side_effect: Callable[[T], None]) -> Iterator[T]:
    """透传,同时执行副作用(用于调试、监控)"""
    for item in source:
        side_effect(item)
        yield item

3.3 实战:电商订单处理流水线

python 复制代码
import json
import hashlib
from datetime import datetime

def read_orders_from_db(batch_size: int = 500) -> Iterator[dict]:
    """
    模拟从数据库分批读取待处理订单。
    真实场景中替换为 SQLAlchemy/pymysql 的分页查询。
    """
    # 模拟数据
    all_orders = [
        {"id": i, "user_id": i % 100, "amount": (i * 7) % 500 + 1,
         "status": "pending", "created_at": "2026-05-10T08:00:00"}
        for i in range(1, 1001)
    ]
    for i in range(0, len(all_orders), batch_size):
        batch = all_orders[i:i + batch_size]
        for order in batch:
            yield order

def validate_order(orders: Iterator[dict]) -> Iterator[dict]:
    """校验订单,过滤无效数据"""
    for order in orders:
        if order.get("amount", 0) <= 0:
            continue
        if not order.get("user_id"):
            continue
        yield order

def enrich_order(orders: Iterator[dict]) -> Iterator[dict]:
    """丰富订单信息:计算税额、生成幂等键"""
    TAX_RATE = 0.08
    for order in orders:
        tax = round(order["amount"] * TAX_RATE, 2)
        idempotency_key = hashlib.md5(
            f"{order['id']}:{order['created_at']}".encode()
        ).hexdigest()
        yield {
            **order,
            "tax": tax,
            "total": round(order["amount"] + tax, 2),
            "idempotency_key": idempotency_key,
            "processed_at": datetime.now().isoformat(),
        }

def route_by_amount(orders: Iterator[dict],
                    threshold: float = 100.0) -> tuple[Iterator[dict], Iterator[dict]]:
    """
    按金额路由:大额订单走人工审核,小额订单自动处理。
    注意:这里不能直接用生成器分叉(因为生成器只能被消费一次)。
    实际生产中通常用两个独立的下游处理器或消息队列实现分叉。
    此函数演示"带条件的写入"模式。
    """
    large_orders = []
    small_orders = []
    for order in orders:
        if order["total"] >= threshold:
            large_orders.append(order)
        else:
            small_orders.append(order)
    return iter(large_orders), iter(small_orders)

def batch_insert(orders: Iterator[dict], batch_size: int = 100) -> Iterator[int]:
    """
    批量写入数据库,每批完成后 yield 本批写入数量(用于进度报告)。
    """
    for batch in gchunk(batch_size, orders):
        # db.bulk_insert("processed_orders", batch)  ← 真实写入
        yield len(batch)  # 报告本批写入了多少条


# -------- 组装流水线 --------

def run_order_pipeline():
    raw        = read_orders_from_db(batch_size=500)
    validated  = validate_order(raw)
    enriched   = enrich_order(validated)

    # 分批写入,同时统计进度
    total = 0
    for batch_count in batch_insert(enriched, batch_size=100):
        total += batch_count
        print(f"已写入 {total} 条订单", end="\r")

    print(f"\n流水线完成,共处理 {total} 条订单")

run_order_pipeline()
# 已写入 100 条订单
# 已写入 200 条订单
# ...
# 流水线完成,共处理 1000 条订单

3.4 流水线的调试技巧

流水线的问题在于:当某一步出错,很难定位是哪个生成器出了问题。gtee 组件在这里大显身手:

python 复制代码
def run_order_pipeline_debug():
    raw = read_orders_from_db()

    # 在每个步骤之间插入探针
    raw       = gtee(raw,       lambda r: None)   # 静默(不影响性能)
    validated = validate_order(raw)
    validated = gtee(validated, lambda r: print(f"[validate] {r['id']}") if r['id'] <= 3 else None)
    enriched  = enrich_order(validated)
    enriched  = gtee(enriched,  lambda r: None)   # 可替换为写入监控指标

    total = sum(batch_insert(enriched))
    print(f"处理完成: {total} 条")

四、场景三:无限序列

4.1 数学序列的惰性表达

无限序列是生成器最自然的使用场景------数学上存在无限的序列(自然数、质数、Fibonacci 数列、等差数列......),但内存是有限的。生成器让"描述无限序列的规则"和"消费序列中的具体元素"完全解耦。

python 复制代码
from itertools import islice

def naturals(start: int = 0) -> Iterator[int]:
    """自然数序列(无限)"""
    n = start
    while True:
        yield n
        n += 1

def primes() -> Iterator[int]:
    """
    质数序列(无限)------筛法生成器实现。
    每产出一个质数,就用它过滤后续候选数。
    """
    def sieve(numbers: Iterator[int], prime: int) -> Iterator[int]:
        for n in numbers:
            if n % prime != 0:
                yield n

    candidates = naturals(2)
    while True:
        prime = next(candidates)
        yield prime
        candidates = sieve(candidates, prime)
        # 注意:这个经典实现会随着质数增多而加深生成器嵌套,
        # 生产环境建议使用下方的分段筛法实现

def primes_segmented(limit: int = None) -> Iterator[int]:
    """
    分段筛法:内存友好,无嵌套生成器深度问题。
    可选 limit 参数,不传则无限产出。
    """
    from math import isqrt

    def sieve_segment(low: int, high: int, small_primes: list) -> list:
        """筛出 [low, high) 范围内的质数"""
        size = high - low
        composite = bytearray(size)  # 0=质数候选,1=合数
        for p in small_primes:
            start = max(p * p, ((low + p - 1) // p) * p)
            for j in range(start - low, size, p):
                composite[j] = 1
        return [low + i for i in range(size) if not composite[i] and low + i >= 2]

    seg_size = 32768  # 每段大小(字节)
    low = 2
    small_primes = []

    count = 0
    while True:
        high = low + seg_size
        segment_primes = sieve_segment(low, high, small_primes)

        # 更新小质数表(用于后续段的筛选)
        if low == 2:
            small_primes = [p for p in segment_primes if p <= isqrt(high)]

        for p in segment_primes:
            yield p
            count += 1
            if limit is not None and count >= limit:
                return

        low = high


def fibonacci() -> Iterator[int]:
    """Fibonacci 数列(无限)"""
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

def geometric(start: float, ratio: float) -> Iterator[float]:
    """等比数列(无限)"""
    value = start
    while True:
        yield value
        value *= ratio

4.2 操作无限序列的工具函数

itertools 标准库提供了一套与无限生成器配合的工具:

python 复制代码
from itertools import (
    islice,    # 从无限序列中取前 N 个
    takewhile, # 取满足条件的前缀
    dropwhile, # 跳过满足条件的前缀
    count,     # 内置无限计数器
    cycle,     # 无限循环序列
    accumulate,# 累积计算
)

# 取前 10 个质数
first_10_primes = list(islice(primes_segmented(), 10))
print(first_10_primes)
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

# 取所有小于 1000 的 Fibonacci 数
small_fib = list(takewhile(lambda x: x < 1000, fibonacci()))
print(small_fib)
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]

# 等比数列求和(取前20项)
geo = geometric(1.0, 0.5)
geo_sum = sum(islice(geo, 20))
print(f"等比数列前20项之和: {geo_sum:.6f}")  # 趋近于 2.0

# 累积求和:产出每一步的前缀和
running_sum = list(islice(accumulate(naturals(1)), 10))
print(running_sum)
# [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]

4.3 工程实战:实时滑动窗口统计

无限序列的典型应用场景之一是实时监控数据流------传感器数据、网络包、API 请求......都是理论上无限的时间序列。

python 复制代码
from collections import deque
from typing import Iterator, Optional

def sliding_window_stats(
    source: Iterator[float],
    window_size: int,
) -> Iterator[dict]:
    """
    对无限数据流执行滑动窗口统计。
    每接收一个新数据点,产出当前窗口的统计信息。
    
    内存消耗:O(window_size),与流的总长度无关。
    """
    window: deque = deque(maxlen=window_size)
    
    for value in source:
        window.append(value)
        if len(window) < window_size:
            continue  # 窗口未满,不产出统计
        
        sorted_window = sorted(window)
        n = len(sorted_window)
        mean = sum(window) / n
        median = (sorted_window[n // 2] if n % 2 == 1
                  else (sorted_window[n // 2 - 1] + sorted_window[n // 2]) / 2)
        variance = sum((x - mean) ** 2 for x in window) / n
        
        yield {
            "mean":   round(mean, 4),
            "median": round(median, 4),
            "std":    round(variance ** 0.5, 4),
            "min":    sorted_window[0],
            "max":    sorted_window[-1],
            "window": list(window),
        }


def simulate_sensor_stream(n_points: int = 50) -> Iterator[float]:
    """模拟传感器数据流(加入随机噪声的正弦波)"""
    import math, random
    for i in range(n_points):
        value = math.sin(i * 0.3) * 10 + random.gauss(0, 0.5)
        yield round(value, 3)


# 对传感器流执行 10 点滑动窗口统计
sensor = simulate_sensor_stream(n_points=30)
stats_stream = sliding_window_stats(sensor, window_size=10)

for i, stats in enumerate(stats_stream):
    print(f"窗口{i+1:2d}: 均值={stats['mean']:6.3f}  "
          f"标准差={stats['std']:.3f}  "
          f"[{stats['min']:.2f}, {stats['max']:.2f}]")

4.4 无限序列与 zip 的组合技

zip 会在最短 的输入耗尽时停止,这使得有限序列和无限序列的 zip 组合成为一种安全的"取前 N 个并附加索引"模式:

python 复制代码
# itertools.count 是内置的无限计数器
from itertools import count

data = ["apple", "banana", "cherry"]

# 用 zip + 无限序列代替 enumerate
for i, item in zip(count(1), data):
    print(f"{i}. {item}")
# 1. apple
# 2. banana
# 3. cherry

# 用 zip + 两个无限序列生成数学表格
fib_gen = fibonacci()
nat_gen = naturals(1)
table = [(f, n, f / n) for f, n in islice(zip(fib_gen, nat_gen), 15)]
for f, n, ratio in table:
    print(f"F({n:2d}) = {f:4d},  F(n)/F(n-1) ≈ {ratio:.4f}")

五、性能陷阱与调优策略

5.1 生成器嵌套过深导致的栈溢出

经典 sieve 实现中,每产出一个质数就会新增一层生成器嵌套,当生成大量质数时会导致 RecursionError

python 复制代码
# 危险:嵌套深度 = 已产出质数数量
gen = primes()  # 经典筛法实现
list(islice(gen, 10000))  # 可能抛出 RecursionError 或极度变慢

解决方案:使用分段筛法primes_segmented)或 itertoolscompress

python 复制代码
from itertools import compress, count as icount

def primes_compress() -> Iterator[int]:
    """使用 compress 的非递归质数生成器"""
    # 这个实现避免了生成器嵌套
    D = {}
    q = 2
    while True:
        if q not in D:
            yield q
            D[q * q] = [q]
        else:
            for p in D[q]:
                D.setdefault(p + q, []).append(p)
            del D[q]
        q += 1

5.2 list(generator) 的内存峰值

生成器表达式传入 list() 时,峰值内存 = 生成器总输出大小(失去了惰性优势):

python 复制代码
# 仅需要总和,不需要中间列表
# 错误:先物化所有数据再求和
total = sum(list(x**2 for x in range(10_000_000)))  # 内存峰值 ~800MB

# 正确:直接聚合
total = sum(x**2 for x in range(10_000_000))  # 内存恒定 ~100B

5.3 与 itertools 的深度配合

python 复制代码
from itertools import chain, starmap, groupby
from operator import itemgetter

# 合并多个日志文件的流(不预先读取任何文件)
def merge_log_files(*filepaths: str) -> Iterator[dict]:
    all_streams = (parse_log_lines(fp) for fp in filepaths)
    return chain.from_iterable(all_streams)

# 按接口路径分组统计(流式版本,要求数据已按 path 排序)
def group_stats(records: Iterator[dict]) -> Iterator[tuple]:
    for path, group in groupby(records, key=itemgetter("path")):
        items = list(group)  # groupby 要求立即消费同组元素
        avg_latency = sum(r["latency_ms"] for r in items) / len(items)
        yield path, len(items), round(avg_latency, 2)

六、生成器流水线的架构全景

消费层(终止点)
sum / max / min

聚合函数
批量写入数据库

batch_insert
写入文件

序列化输出
islice / takewhile

有限截取
变换层(可组合)
gmap

元素变换
gfilter

过滤
gchunk

批次化
gflatmap

展开
gtee

透明监控
数据源层(无限/大规模)
大文件

parse_log_lines
数据库分页

PaginatedQuery
实时传感器

simulate_sensor_stream
无限数学序列

primes / fibonacci

流水线的三层分工:

  • 数据源层:负责产出数据,可以是文件、数据库、网络流、无限序列
  • 变换层 :纯函数变换,无状态(gmap/gfilter)或小状态(gchunk/滑动窗口)
  • 消费层:终止点,触发整个流水线的实际运行(所有生成器都是惰性的,只有被消费时才执行)

七、与标准库的协作

7.1 contextlib.contextmanager:把生成器变上下文管理器

这个话题在后续的文章中会详细展开,但在生成器实战中值得先提一下:

python 复制代码
from contextlib import contextmanager
from typing import Iterator

@contextmanager
def managed_pipeline(filepath: str) -> Iterator[dict]:
    """
    把流水线包装为上下文管理器。
    确保文件在任何情况下都被正确关闭。
    """
    print(f"[pipeline] 开始处理 {filepath}")
    try:
        yield parse_log_lines(filepath)
    finally:
        print(f"[pipeline] 处理完成,资源已释放")

with managed_pipeline("system.log") as records:
    stats = accumulate_stats(only_parsed(records))
    print(stats)

7.2 typing.Generator 的完整签名

python 复制代码
from typing import Generator

# Generator[YieldType, SendType, ReturnType]
def full_typed_gen() -> Generator[int, str, bool]:
    """
    YieldType  = int   ← yield 产出整数
    SendType   = str   ← send() 接收字符串
    ReturnType = bool  ← return 返回布尔值
    """
    received: str = yield 1
    print(f"收到: {received}")
    received = yield 2
    print(f"收到: {received}")
    return True

gen = full_typed_gen()
next(gen)
gen.send("hello")
try:
    gen.send("world")
except StopIteration as e:
    print(f"返回值: {e.value}")  # True

八、模块二完结:从迭代器到生成器的完整知识图谱

迭代器\n与生成器
迭代器协议_05
iter 返回迭代器
next 产出下一个值
StopIteration 终止信号
for 循环语法糖
iter() 两参数哨兵形式
生成器基础_06
yield 暂停执行帧
生成器表达式
惰性求值 内存恒定
生成器流水线
return 附在 StopIteration.value
生成器进阶_07
yield from 三方透明通信
send() 双向通信
throw() 注入异常
close() + GeneratorExit
协程历史 PEP演进
生成器实战_08
大文件流式处理
流水线组件化
无限序列数学结构
滑动窗口统计
itertools 深度配合


小结

  • 大文件场景:逐行生成器 + 流式聚合,内存消耗 O(聚合指标数) 而非 O(文件大小)
  • 流水线场景:每个变换步骤封装为独立生成器,用函数组合而非类继承实现可复用处理器
  • 无限序列场景 :生成器描述"产出规则",itertools.islice/takewhile 决定消费多少
  • 流水线调试利器:gtee 插入透明探针,不影响数据流
  • 性能陷阱:生成器嵌套过深(经典筛法)、list(generator) 破坏惰性

"迭代器与生成器"到这里完整收官。四篇从协议到实现、从概念到场景,把 Python 惰性计算体系的每个环节都拆开看了一遍。如果内容对工程实践有帮助,点赞收藏是继续深挖的最大动力。关注专栏,后续模块持续更新中。

相关推荐
其实防守也摸鱼1 小时前
VS code怎么使用 Conda 安装预编译包
开发语言·网络·c++·vscode·安全·web安全·conda
.柒宇.1 小时前
AI-Agent入门实战-AI私厨
人工智能·python·langchain·agent·fastapi
默子昂1 小时前
langchain 基本使用
开发语言·python·langchain
yaoxin5211231 小时前
402. Java 文件操作基础 - 读取二进制文件
java·开发语言·python
Chase_______2 小时前
计算机数据存储全解:从底层进制转换到存储介质演进
java·开发语言·python
构建的乐趣3 小时前
测度(Measure)和概率测度(Probability Measure) 测度和度量的区别
python
iCxhust3 小时前
8086/8088单板机VSCode集成自动下载功能(完善串口接收显示版)
ide·vscode·单片机·编辑器·微机原理·8088单板机·8086单板机
清水白石0083 小时前
把事故变成护城河:如何设计回归测试,防止“订单重复创建”这类历史 Bug 卷土重来?
python·bug
狐狐生风3 小时前
LangGraph 工具调用集成
python·langchain·prompt·agent·langgraph