学习第 6 天:类型注解、装饰器与高级特性

学习第 6 天:类型注解、装饰器与高级特性


学习目标

  • 掌握 Python 类型注解系统(OptionalUnionTypeVarGeneric
  • 使用 Pydantic v2 进行运行时数据验证------Python 世界的"类型安全防线"
  • 深入理解装饰器原理(闭包 + 函数是一等公民),掌握装饰器实战
  • 掌握生成器(yield)和迭代器协议
  • 为项目添加完整的类型标注和可复用装饰器

为什么学习本章

作为 Java 架构师,你习惯了编译器帮你检查类型。Python 的动态类型让你灵活,但也让你失去了编译时的安全网。本章的两大主题------类型注解和装饰器------恰好解决了这个问题:

  • 类型注解:让你重获"类型提示"的能力,配合 mypy 实现编译时级别的类型检查
  • 装饰器:Python 最优雅的 AOP(面向切面编程)机制------比 Java 的 Proxy/Interceptor 更简洁
  • Pydantic:FastAPI 的基石,也是 LangChain 中广泛使用的数据验证方案

本章在知识体系中的位置

#mermaid-svg-e7Poc540IFhxOtfw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-e7Poc540IFhxOtfw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-e7Poc540IFhxOtfw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-e7Poc540IFhxOtfw .error-icon{fill:#552222;}#mermaid-svg-e7Poc540IFhxOtfw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-e7Poc540IFhxOtfw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-e7Poc540IFhxOtfw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-e7Poc540IFhxOtfw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-e7Poc540IFhxOtfw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-e7Poc540IFhxOtfw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-e7Poc540IFhxOtfw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-e7Poc540IFhxOtfw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-e7Poc540IFhxOtfw .marker.cross{stroke:#333333;}#mermaid-svg-e7Poc540IFhxOtfw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-e7Poc540IFhxOtfw p{margin:0;}#mermaid-svg-e7Poc540IFhxOtfw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-e7Poc540IFhxOtfw .cluster-label text{fill:#333;}#mermaid-svg-e7Poc540IFhxOtfw .cluster-label span{color:#333;}#mermaid-svg-e7Poc540IFhxOtfw .cluster-label span p{background-color:transparent;}#mermaid-svg-e7Poc540IFhxOtfw .label text,#mermaid-svg-e7Poc540IFhxOtfw span{fill:#333;color:#333;}#mermaid-svg-e7Poc540IFhxOtfw .node rect,#mermaid-svg-e7Poc540IFhxOtfw .node circle,#mermaid-svg-e7Poc540IFhxOtfw .node ellipse,#mermaid-svg-e7Poc540IFhxOtfw .node polygon,#mermaid-svg-e7Poc540IFhxOtfw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-e7Poc540IFhxOtfw .rough-node .label text,#mermaid-svg-e7Poc540IFhxOtfw .node .label text,#mermaid-svg-e7Poc540IFhxOtfw .image-shape .label,#mermaid-svg-e7Poc540IFhxOtfw .icon-shape .label{text-anchor:middle;}#mermaid-svg-e7Poc540IFhxOtfw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-e7Poc540IFhxOtfw .rough-node .label,#mermaid-svg-e7Poc540IFhxOtfw .node .label,#mermaid-svg-e7Poc540IFhxOtfw .image-shape .label,#mermaid-svg-e7Poc540IFhxOtfw .icon-shape .label{text-align:center;}#mermaid-svg-e7Poc540IFhxOtfw .node.clickable{cursor:pointer;}#mermaid-svg-e7Poc540IFhxOtfw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-e7Poc540IFhxOtfw .arrowheadPath{fill:#333333;}#mermaid-svg-e7Poc540IFhxOtfw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-e7Poc540IFhxOtfw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-e7Poc540IFhxOtfw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-e7Poc540IFhxOtfw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-e7Poc540IFhxOtfw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-e7Poc540IFhxOtfw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-e7Poc540IFhxOtfw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-e7Poc540IFhxOtfw .cluster text{fill:#333;}#mermaid-svg-e7Poc540IFhxOtfw .cluster span{color:#333;}#mermaid-svg-e7Poc540IFhxOtfw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-e7Poc540IFhxOtfw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-e7Poc540IFhxOtfw rect.text{fill:none;stroke-width:0;}#mermaid-svg-e7Poc540IFhxOtfw .icon-shape,#mermaid-svg-e7Poc540IFhxOtfw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-e7Poc540IFhxOtfw .icon-shape p,#mermaid-svg-e7Poc540IFhxOtfw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-e7Poc540IFhxOtfw .icon-shape .label rect,#mermaid-svg-e7Poc540IFhxOtfw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-e7Poc540IFhxOtfw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-e7Poc540IFhxOtfw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-e7Poc540IFhxOtfw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 第5章

工程化✅
第6章

类型注解装饰器

⬅ 当前
第7章

异步编程


知识体系图

#mermaid-svg-c2jU5QIOaPE1nD7D{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-c2jU5QIOaPE1nD7D .error-icon{fill:#552222;}#mermaid-svg-c2jU5QIOaPE1nD7D .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-c2jU5QIOaPE1nD7D .marker{fill:#333333;stroke:#333333;}#mermaid-svg-c2jU5QIOaPE1nD7D .marker.cross{stroke:#333333;}#mermaid-svg-c2jU5QIOaPE1nD7D svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-c2jU5QIOaPE1nD7D p{margin:0;}#mermaid-svg-c2jU5QIOaPE1nD7D .edge{stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .section--1 rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section--1 path,#mermaid-svg-c2jU5QIOaPE1nD7D .section--1 circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section--1 polygon,#mermaid-svg-c2jU5QIOaPE1nD7D .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section--1 text{fill:#ffffff;}#mermaid-svg-c2jU5QIOaPE1nD7D .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-depth--1{stroke-width:17;}#mermaid-svg-c2jU5QIOaPE1nD7D .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled circle,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:lightgray;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:#efefef;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-0 rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section-0 path,#mermaid-svg-c2jU5QIOaPE1nD7D .section-0 circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section-0 polygon,#mermaid-svg-c2jU5QIOaPE1nD7D .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section-0 text{fill:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .node-icon-0{font-size:40px;color:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-depth-0{stroke-width:14;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled circle,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:lightgray;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:#efefef;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-1 rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section-1 path,#mermaid-svg-c2jU5QIOaPE1nD7D .section-1 circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section-1 polygon,#mermaid-svg-c2jU5QIOaPE1nD7D .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section-1 text{fill:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .node-icon-1{font-size:40px;color:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-depth-1{stroke-width:11;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled circle,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:lightgray;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:#efefef;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-2 rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section-2 path,#mermaid-svg-c2jU5QIOaPE1nD7D .section-2 circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section-2 polygon,#mermaid-svg-c2jU5QIOaPE1nD7D .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section-2 text{fill:#ffffff;}#mermaid-svg-c2jU5QIOaPE1nD7D .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-depth-2{stroke-width:8;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled circle,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:lightgray;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:#efefef;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-3 rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section-3 path,#mermaid-svg-c2jU5QIOaPE1nD7D .section-3 circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section-3 polygon,#mermaid-svg-c2jU5QIOaPE1nD7D .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section-3 text{fill:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .node-icon-3{font-size:40px;color:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-depth-3{stroke-width:5;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled circle,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:lightgray;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:#efefef;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-4 rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section-4 path,#mermaid-svg-c2jU5QIOaPE1nD7D .section-4 circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section-4 polygon,#mermaid-svg-c2jU5QIOaPE1nD7D .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section-4 text{fill:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .node-icon-4{font-size:40px;color:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-depth-4{stroke-width:2;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled circle,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:lightgray;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:#efefef;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-5 rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section-5 path,#mermaid-svg-c2jU5QIOaPE1nD7D .section-5 circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section-5 polygon,#mermaid-svg-c2jU5QIOaPE1nD7D .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section-5 text{fill:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .node-icon-5{font-size:40px;color:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-depth-5{stroke-width:-1;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled circle,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:lightgray;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:#efefef;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-6 rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section-6 path,#mermaid-svg-c2jU5QIOaPE1nD7D .section-6 circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section-6 polygon,#mermaid-svg-c2jU5QIOaPE1nD7D .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section-6 text{fill:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .node-icon-6{font-size:40px;color:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-depth-6{stroke-width:-4;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled circle,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:lightgray;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:#efefef;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-7 rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section-7 path,#mermaid-svg-c2jU5QIOaPE1nD7D .section-7 circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section-7 polygon,#mermaid-svg-c2jU5QIOaPE1nD7D .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section-7 text{fill:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .node-icon-7{font-size:40px;color:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-depth-7{stroke-width:-7;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled circle,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:lightgray;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:#efefef;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-8 rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section-8 path,#mermaid-svg-c2jU5QIOaPE1nD7D .section-8 circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section-8 polygon,#mermaid-svg-c2jU5QIOaPE1nD7D .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section-8 text{fill:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .node-icon-8{font-size:40px;color:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-depth-8{stroke-width:-10;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled circle,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:lightgray;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:#efefef;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-9 rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section-9 path,#mermaid-svg-c2jU5QIOaPE1nD7D .section-9 circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section-9 polygon,#mermaid-svg-c2jU5QIOaPE1nD7D .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section-9 text{fill:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .node-icon-9{font-size:40px;color:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-depth-9{stroke-width:-13;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled circle,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:lightgray;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:#efefef;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-10 rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section-10 path,#mermaid-svg-c2jU5QIOaPE1nD7D .section-10 circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section-10 polygon,#mermaid-svg-c2jU5QIOaPE1nD7D .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section-10 text{fill:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .node-icon-10{font-size:40px;color:black;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .edge-depth-10{stroke-width:-16;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled circle,#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:lightgray;}#mermaid-svg-c2jU5QIOaPE1nD7D .disabled text{fill:#efefef;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-root rect,#mermaid-svg-c2jU5QIOaPE1nD7D .section-root path,#mermaid-svg-c2jU5QIOaPE1nD7D .section-root circle,#mermaid-svg-c2jU5QIOaPE1nD7D .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-c2jU5QIOaPE1nD7D .section-root text{fill:#ffffff;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-root span{color:#ffffff;}#mermaid-svg-c2jU5QIOaPE1nD7D .section-2 span{color:#ffffff;}#mermaid-svg-c2jU5QIOaPE1nD7D .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-c2jU5QIOaPE1nD7D .edge{fill:none;}#mermaid-svg-c2jU5QIOaPE1nD7D .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-c2jU5QIOaPE1nD7D :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 第6章:类型与装饰器
类型注解
基础注解
Optional_Union
TypeVar_Generic
TypedDict
Protocol
Pydantic v2
模型定义
验证器
序列化
mypy
静态检查
配置
装饰器
原理 闭包
自定义装饰器
带参数装饰器
functools.wraps
常用装饰器
生成器
yield
yield from
生成器表达式


一、核心知识

1.1 类型注解基础

Python 的类型注解是可选的、不影响运行时的元数据------但配合 Pydantic 和 mypy,它能提供媲美静态语言的安全感:

python 复制代码
# 基础注解
name: str = "Agent"
version: float = 1.0
is_active: bool = True
scores: list[int] = [85, 92, 78]
config: dict[str, str | int] = {"model": "gpt-4o", "tokens": 4096}

# 函数注解
def process_message(
    content: str,
    temperature: float = 0.7,
    tools: list[str] | None = None,
) -> str:
    """content 必传,tools 可选,返回 str"""
    return content.upper()

# Optional[X] = X | None
from typing import Optional
def find_agent(name: str) -> Optional[dict]:
    ...

# Union------Python 3.10+ 用 | 替代
from typing import Union
def get_value() -> Union[str, int]: ...   # 旧
def get_value() -> str | int: ...         # 新(推荐)

1.2 进阶类型

python 复制代码
from typing import TypeVar, Generic, Protocol, TypedDict

# TypeVar------泛型变量
T = TypeVar("T")

class Repository(Generic[T]):
    def get(self, id: str) -> T | None: ...
    def save(self, entity: T) -> None: ...

# 使用------类型安全!
agent_repo: Repository["Agent"] = Repository()
agent = agent_repo.get("1")  # IDE 知道 agent 是 Agent 类型

# Protocol------结构化类型(鸭子类型的类型注解版)
class Processable(Protocol):
    def process(self, input: str) -> str: ...

def run_pipeline(processor: Processable, messages: list[str]):
    return [processor.process(m) for m in messages]

# TypedDict------类型化的字典
class AgentConfig(TypedDict):
    name: str
    model: str
    temperature: float

1.3 Pydantic v2------运行时验证

Pydantic 是 Python 数据验证的事实标准。它比 @dataclass 更强大------自动类型转换、验证、序列化:

python 复制代码
from pydantic import BaseModel, Field, field_validator
from datetime import datetime
from enum import Enum

class AgentStatus(str, Enum):
    ACTIVE = "active"
    INACTIVE = "inactive"

class AgentCreate(BaseModel):
    """创建 Agent 的请求模型"""
    name: str = Field(..., min_length=2, max_length=50, description="Agent 名称")
    model: str = Field(default="gpt-4o", description="模型名称")
    temperature: float = Field(default=0.7, ge=0, le=2)
    tools: list[str] = Field(default_factory=list)
    
    @field_validator("name")
    @classmethod
    def name_must_not_contain_special_chars(cls, v: str) -> str:
        if "<" in v or ">" in v:
            raise ValueError("Name contains invalid characters")
        return v.strip()

class AgentResponse(BaseModel):
    """Agent 响应模型"""
    id: str
    name: str
    model: str
    status: AgentStatus
    created_at: datetime
    
    model_config = {"from_attributes": True}  # 可从 ORM 对象创建

# 使用
data = {"name": "  assistant  ", "temperature": 0.9, "tools": ["search"]}
agent = AgentCreate(**data)
print(agent.name)          # "assistant" ------ 自动去空白
print(agent.model_dump())  # 序列化为 dict
# 如果 name="a" --- ValidationError: 长度至少为 2

二、详细知识讲解

2.1 装饰器原理

装饰器本质上是一个接受函数、返回新函数的高阶函数

python 复制代码
import functools
import time

# 基础装饰器
def log_execution(func):
    """记录函数执行日志"""
    @functools.wraps(func)  # 保留原函数的元数据(__name__、__doc__)
    def wrapper(*args, **kwargs):
        print(f"[LOG] Calling {func.__name__}")
        result = func(*args, **kwargs)
        print(f"[LOG] {func.__name__} returned {result}")
        return result
    return wrapper

@log_execution                    # @ 语法糖等价于 greet = log_execution(greet)
def greet(name: str) -> str:
    """Say hello"""
    return f"Hello, {name}"

print(greet.__name__)  # "greet"(有 @wraps)
print(greet("Agent"))  # [LOG] Calling greet / [LOG] greet returned Hello, Agent

带参数的装饰器(三层嵌套)

python 复制代码
# 装饰器工厂------接受参数,返回真正的装饰器
def retry(max_attempts: int = 3, delay: float = 1.0):
    """失败自动重试"""
    import time as _time
    
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            last_error = None
            for attempt in range(1, max_attempts + 1):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    last_error = e
                    if attempt < max_attempts:
                        print(f"Retry {attempt}/{max_attempts} after {delay}s...")
                        _time.sleep(delay)
            raise last_error
        return wrapper
    return decorator

@retry(max_attempts=3, delay=0.5)
def call_llm(prompt: str) -> str:
    # 模拟不稳定调用
    import random
    if random.random() < 0.7:
        raise ConnectionError("Network error")
    return f"Response: {prompt}"

常用装饰器实现

python 复制代码
# 缓存装饰器
def cache_result(func):
    """简单内存缓存"""
    cache = {}
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        key = (args, tuple(sorted(kwargs.items())))
        if key not in cache:
            cache[key] = func(*args, **kwargs)
        return cache[key]
    return wrapper

# 计时装饰器
def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        print(f"{func.__name__} took {elapsed:.4f}s")
        return result
    return wrapper

2.2 生成器

生成器是惰性求值的迭代器 ,用 yield 而不是 return。它在 AI Agent 开发中极其重要------流式处理 LLM 输出:

python 复制代码
# 生成器函数
def generate_ids(count: int):
    """逐个生成 ID,不一次性创建列表"""
    for i in range(count):
        yield f"agent_{i:04d}"

# 惰性迭代------内存占用极小
for agent_id in generate_ids(1_000_000):
    if agent_id == "agent_0003":
        print(agent_id)
        break  # 只生成了 4 个,不是 100 万个

# yield from------委托给子生成器
def generate_all():
    yield from generate_ids(3)
    yield from ["special_1", "special_2"]

生成器表达式

python 复制代码
# 列表------一次性创建,占用内存
squares_list = [x**2 for x in range(1_000_000)]  # 内存爆炸

# 生成器表达式------惰性求值
squares_gen = (x**2 for x in range(1_000_000))   # 几乎不占内存
print(next(squares_gen))  # 1
print(next(squares_gen))  # 4

# 管道式处理(每个元素流经整个管道,而非每步全部处理完)
messages = (m.strip() for m in raw_lines)
non_empty = (m for m in messages if m)
processed = (f"[{m}]" for m in non_empty)
for msg in processed:
    print(msg)

2.3 迭代器协议

python 复制代码
# 任何实现了 __iter__ 和 __next__ 的对象都是迭代器
class ConversationStream:
    """对话流迭代器"""
    def __init__(self, messages: list[str]):
        self.messages = messages
        self.index = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index >= len(self.messages):
            raise StopIteration
        msg = self.messages[self.index]
        self.index += 1
        return msg

# for 循环自动使用迭代器协议
for msg in ConversationStream(["Hi", "How are you?"]):
    print(msg)

2.4 @staticmethod 与 @classmethod 对比

两者都是定义在类内部的"特殊方法",但用途完全不同。Java 开发者容易混淆------本节一次性讲清楚:

python 复制代码
class AgentFactory:
    """Agent 工厂------展示三种方法类型的实际使用"""

    default_model = "gpt-4o"  # 类变量

    def __init__(self, api_key: str):
        """实例方法------第一个参数是 self(实例本身)"""
        self.api_key = api_key

    def create_agent(self, name: str) -> dict:
        """实例方法:可以访问 self.api_key 和 self.default_model"""
        return {
            "name": name,
            "model": self.default_model,
            "api_key_prefix": self.api_key[:7],
        }

    @classmethod
    def from_env(cls) -> "AgentFactory":
        """类方法------第一个参数是 cls(类本身),可以访问类变量。

        典型用途:替代构造函数(工厂方法模式)"""
        import os
        api_key = os.getenv("OPENAI_API_KEY", "sk-default")
        return cls(api_key)

    @classmethod
    def with_model(cls, model: str) -> "AgentFactory":
        """类方法:创建特定配置的工厂"""
        instance = cls("sk-default")
        instance.default_model = model
        return instance

    @staticmethod
    def validate_name(name: str) -> bool:
        """静态方法------不需要 self 也不需要 cls,纯工具函数。

        放在类内部只是逻辑上属于这个类,本质和模块级函数无异。

        典型用途:工具/验证函数、工厂辅助逻辑"""
        return 2 <= len(name.strip()) <= 50


# === 三种方法的调用方式 ===

# 实例方法:通过实例调用
factory = AgentFactory("sk-abc123")
agent = factory.create_agent("MyAgent")  # ✅

# 类方法:通过类调用(自动传入 cls)
factory2 = AgentFactory.from_env()        # ✅ 替代构造函数

# 静态方法:通过类或实例都可调用
AgentFactory.validate_name("MyAgent")     # ✅ 类调用
factory.validate_name("MyAgent")          # ✅ 实例调用(但不推荐)
方法类型 第一个参数 可访问类变量 可访问实例变量 典型用途
实例方法 def f(self) self(实例) 核心业务逻辑
类方法 @classmethod cls(类) 替代构造函数、工厂模式
静态方法 @staticmethod 工具函数、验证逻辑

Java 对照@classmethod ≈ Java 的静态工厂方法(如 LocalDate.of()),@staticmethod ≈ Java 的 static 方法。关键区别:Python 的 @classmethod 可以被子类继承并传入子类的 cls,实现多态。

2.5 contextlib.contextmanager ------ 上下文管理器装饰器

在第 4 章我们学习了 with 语句和 __enter__/__exit__ 魔术方法。@contextmanager 提供了更简洁的方式:

python 复制代码
from contextlib import contextmanager
import time


# ===== 方式 1:基于类的上下文管理器(第 4 章回顾) =====
class Timer:
    """计时器------with Timer() as t: ..."""
    def __enter__(self):
        self.start = time.perf_counter()
        return self

    def __exit__(self, *args):
        self.elapsed = time.perf_counter() - self.start
        print(f"耗时: {self.elapsed:.4f}s")


# ===== 方式 2:@contextmanager 装饰器 ------ 更简洁! =====
@contextmanager
def timer(name: str = "操作"):
    """计时上下文管理器------yield 前是 __enter__,yield 后是 __exit__"""
    start = time.perf_counter()
    print(f"[{name}] 开始...")
    try:
        yield  # ← 控制权交给 with 块内的代码
    finally:
        elapsed = time.perf_counter() - start
        print(f"[{name}] 完成,耗时 {elapsed:.4f}s")


# 使用
with timer("LLM调用"):
    time.sleep(0.1)
# 输出:
# [LLM调用] 开始...
# [LLM调用] 完成,耗时 0.1002s


# ===== 实用案例:临时修改环境变量 =====
import os

@contextmanager
def set_env(**kwargs):
    """临时设置环境变量,with 块结束后自动恢复"""
    original = {}
    for key, value in kwargs.items():
        original[key] = os.environ.get(key)
        os.environ[key] = value
    try:
        yield
    finally:
        for key, value in original.items():
            if value is None:
                os.environ.pop(key, None)
            else:
                os.environ[key] = value

# 使用
with set_env(LOG_LEVEL="DEBUG", TIMEOUT="60"):
    print(os.environ["LOG_LEVEL"])  # "DEBUG"
print(os.environ.get("LOG_LEVEL", "未设置"))  # "未设置"(已恢复)


# ===== 实用案例:数据库事务管理 =====
@contextmanager
def db_transaction(connection):
    """自动管理数据库事务:成功则提交,失败则回滚"""
    print("BEGIN TRANSACTION")
    try:
        yield connection
        print("COMMIT")
    except Exception:
        print("ROLLBACK")
        raise


# 模拟使用
class FakeDB:
    def execute(self, sql): print(f"  SQL: {sql}")

db = FakeDB()
with db_transaction(db) as conn:
    conn.execute("INSERT INTO agents VALUES (1, 'test')")
    conn.execute("UPDATE agents SET status='active' WHERE id=1")
# 输出:
# BEGIN TRANSACTION
#   SQL: INSERT INTO agents VALUES (1, 'test')
#   SQL: UPDATE agents SET status='active' WHERE id=1
# COMMIT

Java 对照@contextmanager ≈ Java 的 try-with-resources + AutoCloseable,但更灵活------可以用在任意逻辑上,不限于资源释放。

2.6 mypy 实战------Python 的"编译时"类型检查

mypy 是 Python 社区事实标准的静态类型检查工具。它不运行代码,只检查类型注解的正确性------相当于 Java 编译器做的类型检查,但是可选的、渐进式的:

python 复制代码
# ===== mypy 会捕获的错误 =====

# ❌ 类型不匹配
def greet(name: str) -> str:
    return 42  # mypy: error: Incompatible return value type (got "int", expected "str")


# ❌ 可能为 None 但未检查
def process(data: str | None) -> str:
    return data.upper()  # mypy: error: Item "None" of "str | None" has no attribute "upper"

# ✅ 正确:先检查 None
def process_safe(data: str | None) -> str:
    if data is None:
        return ""
    return data.upper()


# ❌ 参数类型不匹配
def create_agent(name: str, temperature: float) -> dict:
    return {"name": name, "temp": temperature}

create_agent(123, "0.7")  # mypy: 两个参数类型都错了!

mypy 配置

toml 复制代码
# pyproject.toml 中添加 mypy 配置
[tool.mypy]
python_version = "3.12"
strict = false  # 逐步启用严格模式

# 基础检查(建议全部开启)
warn_return_any = true
warn_unused_configs = true
warn_redundant_casts = true
warn_unused_ignores = true
no_implicit_optional = true

# 函数相关
disallow_untyped_defs = true       # 所有函数必须有类型注解
disallow_incomplete_defs = true    # 所有参数必须有类型注解
check_untyped_defs = true

# 严格模式(企业项目推荐逐步启用)
# strict = true  # 开启所有严格检查

# 第三方库的类型存根
[[tool.mypy.overrides]]
module = ["pydantic", "fastapi", "httpx"]
ignore_missing_imports = true  # 缺少类型存根的库忽略

渐进式采用策略

bash 复制代码
# 第 1 步:安装 mypy
uv add --dev mypy

# 第 2 步:在项目中运行(会看到很多错误,正常)
uv run mypy src/

# 第 3 步:先处理公共 API 的类型错误
uv run mypy src/agent_platform/api/ src/agent_platform/services/

# 第 4 步:逐步启用严格检查
# 在 pyproject.toml 中逐步开启 disallow_untyped_defs 等选项

# 第 5 步:加入 CI/CD 流程(可选)
# uv run mypy src/ --strict

Java 对照:mypy ≈ Java 编译器的类型检查阶段,但它不阻止代码运行------即使 mypy 报错,代码仍然可以正常执行。这体现了 Python "类型注解是可选元数据" 的设计哲学。


三、代码示例

示例 1:Pydantic 验证的 Agent 配置系统

python 复制代码
from pydantic import BaseModel, Field, model_validator
from typing import Any


class LLMConfig(BaseModel):
    model: str = "gpt-4o"
    temperature: float = Field(default=0.7, ge=0, le=2)
    max_tokens: int = Field(default=4096, gt=0)


class AgentConfig(BaseModel):
    name: str = Field(..., min_length=2, max_length=50)
    llm: LLMConfig = Field(default_factory=LLMConfig)
    tools: list[str] = Field(default_factory=list)
    memory_enabled: bool = False
    
    @model_validator(mode="after")
    def validate_tools(self) -> "AgentConfig":
        if "search" in self.tools and not self.memory_enabled:
            raise ValueError("Search tool requires memory_enabled=True")
        return self


# 验证通过
config = AgentConfig(name="assistant", llm={"temperature": 0.9})
print(config.model_dump())

# 验证失败
try:
    AgentConfig(name="a", tools=["search"])  # name 太短 + search 需要 memory
except Exception as e:
    print(e)

示例 2:可组合的装饰器栈

python 复制代码
import functools, time, logging

def log_call(level=logging.INFO):
    def deco(func):
        @functools.wraps(func)
        def wrapper(*a, **kw):
            logging.log(level, f"→ {func.__name__}")
            r = func(*a, **kw)
            logging.log(level, f"← {func.__name__}")
            return r
        return wrapper
    return deco

def retry(max_times=3):
    def deco(func):
        @functools.wraps(func)
        def wrapper(*a, **kw):
            for i in range(max_times):
                try: return func(*a, **kw)
                except Exception as e:
                    if i == max_times - 1: raise
                    time.sleep(0.5)
        return wrapper
    return deco

@log_call()
@retry(max_times=2)
def unstable_api_call(text: str) -> str:
    import random
    if random.random() < 0.5:
        raise ConnectionError("fail")
    return f"OK: {text}"

# 执行顺序:log_call(retry(original))
# 1. log_call wrapper 进入
# 2. retry wrapper 执行(含重试逻辑)
# 3. 原始函数执行
# 4. retry wrapper 退出
# 5. log_call wrapper 退出

四、实战案例

案例 1:Token 用量追踪装饰器

python 复制代码
import functools, time
from collections import defaultdict

# 全局统计
token_stats: dict[str, dict] = defaultdict(lambda: {"calls": 0, "tokens": 0})


def track_tokens(agent_name: str):
    """追踪 Agent 的 Token 用量"""
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            start = time.perf_counter()
            result = func(*args, **kwargs)
            elapsed = time.perf_counter() - start

            # 模拟从返回值提取 token 数
            tokens = len(str(result)) // 4
            token_stats[agent_name]["calls"] += 1
            token_stats[agent_name]["tokens"] += tokens

            print(f"[{agent_name}] +{tokens} tokens ({elapsed:.2f}s) | "
                  f"total: {token_stats[agent_name]['tokens']}")
            return result
        return wrapper
    return decorator


@track_tokens("assistant")
def call_gpt(prompt: str) -> str:
    time.sleep(0.1)
    return f"Response to: {prompt}"

call_gpt("Hello")
call_gpt("How are you?")

案例 2:生成器实现流式对话

python 复制代码
from typing import Generator
import time


def stream_chat_response(prompt: str) -> Generator[str, None, None]:
    """模拟 LLM 逐 Token 流式输出"""
    response = f"Based on your question '{prompt[:20]}...', here is my analysis: "
    words = response.split()
    for word in words:
        yield word + " "
        time.sleep(0.05)  # 模拟网络延迟
    yield "\n\nKey points:\n"
    for i, point in enumerate(["Point one", "Point two", "Point three"], 1):
        yield f"{i}. {point}\n"
        time.sleep(0.1)


# 流式消费
print("🤖 Agent: ", end="", flush=True)
for chunk in stream_chat_response("Tell me about Python"):
    print(chunk, end="", flush=True)

五、Java 开发者对照学习

概念 Java Python
类型泛型 <T> TypeVar("T") + Generic[T]
接口类型 interface Processable Protocol
AOP Spring AOP / Proxy / Interceptor 装饰器
数据验证 Bean Validation / @NotNull Pydantic Field(...)
静态检查 编译器 mypy / pyright
惰性序列 Stream<T> 生成器 (x for x in ...)
注解 @Annotation(元数据) @decorator(修改行为)

装饰器 vs Java 注解

  • Java 注解是元数据------需要框架(Spring/反射)解释执行
  • Python 装饰器是运行时代码------直接替换/包装函数,无需额外框架

六、企业最佳实践

  1. Pydantic > dataclass:当需要验证、序列化、OpenAPI schema 时
  2. 装饰器保持单一职责:一个装饰器只做一件事
  3. 永远使用 @functools.wraps:保留函数签名和文档
  4. yield 流式处理大数据:LLM 输出、文件读取、ETL 管道
  5. 类型注解渐进式:先公共 API,再内部函数,最后复杂泛型

七、常见错误

错误 说明
装饰器忘记 @wraps 丢失函数名和文档字符串
生成器只遍历一次 (x for x in data) 消费后为空
TypeVar 忘记绑定 泛型失去类型约束
Pydantic 模型可变默认值 list/dictdefault_factory

八、本章总结

类型注解让你重获类型安全感;Pydantic 是数据验证的终极武器;装饰器替代了 Java 的 AOP;生成器是大数据和流式处理的基石。


九、面试题

  1. 装饰器的本质是什么?@functools.wraps 的作用?
  2. TypeVar 和 Java 的 <T> 的异同?
  3. 生成器和列表的区别?何时用生成器?
  4. Pydantic BaseModel@dataclass 的核心区别?
  5. 如何实现带参数的装饰器?

十、练习题

  1. AgentService 类的方法添加完整的类型注解
  2. 实现 @validate_input 装饰器------用 Pydantic 验证函数参数
  3. 用生成器实现一个"分页数据加载器"
  4. 实现 @singleton 装饰器
  5. 定义 MessageProtocol------用 Protocol 约束消息处理接口
  6. 用 Pydantic 定义 ToolCallToolResult 模型
  7. 实现 @deprecated 装饰器
  8. 写一个生成器实现斐波那契数列
  9. TypedDict 定义 LLM API 响应的类型
  10. 实现装饰器组合工具函数

十一、今日作业

基础:为项目所有公共函数/类添加类型注解

中等 :实现 @retry@log_call@cache_result 三个装饰器并应用到 Agent 服务中

挑战 :实现 @validate_response(pydantic_model) 装饰器------自动验证函数返回值是否符合 Pydantic 模型


十二、预习下一章

第 7 章:异步编程------asyncio 事件循环、async/await、协程、并发控制。这是调用 LLM API(IO 密集型)的核心技能。

相关推荐
minglie11 小时前
线性电枢和分圆多项式
学习
汉堡包0011 小时前
【工具分享】--威胁情报平台大全
学习·安全·web安全·信息安全
码云骑士2 小时前
80-指令微调Instruction-Tuning-指令数据构造-多任务训练-过拟合检测
python
爱昏羔2 小时前
上篇:从PDF到向量库 — 物流行业RAG系统的知识库构建全解析
python·langchain·pdf·agent·rag
麻雀飞吧2 小时前
最新量化实现难点,规则和流程要先有形状
人工智能·python
用户0332126663672 小时前
使用 Python 在 Word 文档中添加或删除文本框
python
旺仔学长 哈哈3 小时前
55384 消防安全教育与逃生演练小程序:知识学习、案例浏览和在线演练一站式实现
学习·小程序·消防教育·逃生演练
LadenKiller3 小时前
近期AI量化辅助,工具重点要跟学习阶段变化
人工智能·python
今夜有雨.3 小时前
C++JSON 解析器
c++·笔记·后端·学习·json