Python装饰器从入门到精通:原理、实战与避坑指南
有一段时间我负责一个内部数据平台某天用户报了个bug同一个报表任务被重复执行了两次。我沿着调用链查了半天最后发现问题压根不在业务逻辑里而是出在一个装饰器上——当时图省事给某个函数加了日志但日志器上被重复挂了两遍handler同一件事打了两次。这让我意识到好多人和当时的我一样天天在用Python装饰器却未必真理解它到底在做什么、什么时候该用、什么时候不该用。这篇内容就是围绕Python装饰器从入门到精通的完整梳理。我会先讲清楚装饰器解决的核心问题再从闭包和一等函数这个底层原理入手然后一步步写出能处理参数、保留函数元信息的装饰器再扩展到带参数的装饰器和类装饰器提供日志、计时、重试、缓存这四类拿来就能用的实战装饰器最后把我从生产环境里撕下来的几个坑分享出来。适合刚学Python想搞懂装饰器的入门者也适合写了好几年装饰器但总觉得哪里没吃透的老手。1. 为什么需要装饰器从一个排查到半夜的bug说起那个报表重复执行的现场最后定位到的是一个日志装饰器。当时我在多个模块里给不同函数加上log_execution想看到每个函数的调用时间。装饰器本身没问题问题在于装饰器内部用了同一个全局Logger又反复addHandler导致一次调用被多次输出。这其实暴露了一个本质问题日志、计时、鉴权、重试这类逻辑和业务逻辑无关但它们会散落在几乎所有函数里。1.1 装饰器解决的痛点横切关注点在任何一个稍有规模的项目里你都会遇到一种情况一个函数除了做自己的本职工作外还要处理权限校验、参数校验、调用计时、异常重试、结果缓存……如果把这些代码直接写在每个函数内部大概会这样def query_user(user_id): start time.perf_counter() if not check_permission(current_user): raise PermissionError(没有权限) result db.query(user_id) logger.info(fquery_user cost {time.perf_counter() - start:.4f}s) return result def query_order(order_id): start time.perf_counter() if not check_permission(current_user): raise PermissionError(没有权限) result db.query(order_id) logger.info(fquery_order cost {time.perf_counter() - start:.4f}s) return result一旦这种需求多起来代码会迅速膨胀每个函数里都埋伏着五六行与核心业务无关的样板代码改一个权限校验逻辑就要全局搜索替换。这种分布在多个模块、与核心业务逻辑正交的关注点就叫“横切关注点”。装饰器正是为了对付这类场景设计的把横切逻辑抽到一个独立的增强函数里再通过语法“贴”到目标函数上业务函数本身保持干净。1.2 判断你是不是真的需要装饰器装饰器不是银弹我见过不少为了用装饰器而用装饰器的代码反而把调用链搞得很难追踪。我自己的判断标准很简单需要反复复用的增强逻辑比如鉴权、重试、缓存——适合装饰器。只在一个地方用的简单逻辑——直接写在函数内部或抽成普通函数调用即可。需要运行时动态决定扩展方式的比如插件架构——装饰器加注册表模式很好用。只是临时调试打印几个值——别包装饰器print加完记得删否则时间一长就成了没人敢动的历史包袱。另外要注意装饰器一旦上线函数名虽然没变但它的类型、签名、属性都可能被“换了一层皮”。这也是后文我要专门讲functools.wraps的原因。2. 真正看懂装饰器先从闭包和一等函数说起很多人卡在装饰器上不是不理解符号而是没搞明白闭包。装饰器本质上是闭包的一种应用而闭包又依赖于“函数是一等公民”这件事。2.1 函数是一等公民在Python里函数和整数、字符串、列表一样可以被赋值给变量可以作为参数传给其他函数也可以作为返回值从函数里返回。这听起来稀松平常但很多从C或Java转过来的人会在这里卡一下def say_hello(): return hello f say_hello # 不调用只是把函数对象赋值给f print(f()) # 通过f调用原函数再比如高阶函数def apply_twice(func, value): return func(func(value)) print(apply_twice(lambda x: x 3, 5)) # 5 - 8 - 11这里func就是一个被当成普通数据传来传去的函数。这一等公民的身份是我们能“把一个函数交给另一个函数去增强”的前提。2.2 闭包是函数加上自由变量的组合体闭包的定义听起来玄乎内层函数引用了外层函数作用域里的变量并且在外层函数执行结束后内层函数依然持有那些变量。为什么能持有因为Python在编译时发现内层引用了外层变量就会把这个变量装进一个cell对象里内层函数和这个cell对象被绑定在一起形成一个闭包。来看一个教科书级例子def make_multiplier(factor): def multiply(x): return x * factor return multiply double make_multiplier(2) triple make_multiplier(3) print(double(10)) # 20 print(triple(10)) # 30double和triple是同一个函数模板multiply生成的两个不同闭包它们各自保存了不同的factor值。外层函数make_multiplier(2)早就执行完了但闭包里的factor仍然活着。这里有个特别容易踩的坑闭包捕获的是变量的引用不是创建时的值。很多人第一次遇到下面这个结果会懵funcs [] for i in range(3): funcs.append(lambda: i) for f in funcs: print(f()) # 输出 2 2 2而不是 0 1 2循环结束后i变成了2而每个lambda闭包引用的都是同一个变量i的当前值。修复方式是用默认参数把i“定格”住lambda xi: x。装饰器里的闭包变量也一样如果你在装饰器内部用循环变量一样会碰上这个坑我在第六部分会再提到。2.3 内层wrapper为什么必须存在装饰器要做的不是“替换”原函数而是“包一层”。外层接收原函数内层函数负责增强逻辑同时保留调用原函数的能力。正因为Python函数可以返回函数我们才能写出def my_decorator(func): def wrapper(): print(调用前) func() print(调用后) return wrapper这里的wrapper就是一个闭包它引用着外层参数func。我们把wrapper返回出去替换掉原来的func。调用者仍然用原函数名调用实际上执行的是wrapper。这个“包一层”的思想是所有装饰器的核心骨架后面的花样再多底子都是这个闭包结构。3. 手写第一个装饰器参数、返回值、元信息一个都不能少原理搞清楚了现在开始写代码。我从最简单的版本写起然后一步步补齐真实的装饰器必备的三件事参数透传、返回值透传、函数元信息保留。3.1 最简单的装饰器长什么样import time def time_it(func): def wrapper(*args, **kwargs): start time.perf_counter() result func(*args, **kwargs) cost time.perf_counter() - start print(f{func.__name__} 耗时 {cost * 1000:.2f} ms) return result return wrapper time_it def compute_square(n): time.sleep(0.1) return n * n print(compute_square(5))time_it等价于compute_square time_it(compute_square)只是语法糖。看到这里你会发现装饰器就是一个普通函数接收函数对象返回一个新的函数对象。注意wrapper里的*args, **kwargs这一行很重要它负责把原函数的所有参数接住并转交给func。只有这样才能让装饰器既能装饰无参函数也能装饰有参函数、有默认参数的函数、有关键字参数的函数。3.2 返回值为什么必须return我在第一版装饰器里踩过一个大坑忘了在wrapper里写return result。表面上看打印时间都正常但函数调用结果全是None。原因很简单wrapper是真正被调用的函数它自己必须把func的返回值“递”出去否则等于把结果吞了。def bad_decorator(func): def wrapper(*args, **kwargs): func(*args, **kwargs) # 没有return return wrapper bad_decorator def add(a, b): return a b print(add(1, 2)) # None这种bug极其隐蔽因为函数过程没有报错只有在你检查返回值时才暴露。所以写装饰器有个强制习惯只要包装的函数有返回值wrapper里必须return result。甚至我建议不管原函数有没有返回值都先把返回值透传因为你没法预测函数以后会不会加return。3.3 functools.wraps到底修了什么如果直接写上面那种装饰器会把原函数的__name__、__doc__、__module__等信息全部替换成wrapper的。这在调试和文档生成时非常讨厌print(compute_square.__name__) # wrapper不是 compute_square import inspect print(inspect.signature(compute_square)) # (*args, **kwargs)不是 (n)修复方法是用标准库自带的functools.wrapsimport functools def time_it(func): functools.wraps(func) def wrapper(*args, **kwargs): ... return wrapperwraps做两件事第一把原函数的__name__、__doc__、__module__、__qualname__等属性拷贝到wrapper上第二给wrapper设置__wrapped__ func。有了__wrapped__inspect.signature这类工具就能顺着它找到原始签名。所以我的标准装饰器模板一定是带functools.wraps(func)的否则以后接手代码的人会活得很难受。4. 进阶用法带参数的装饰器、类装饰器以及叠加顺序基础装饰器能处理大部分情况但你会发现总有些需求需要给装饰器本身传参数比如retry(times3)、cache(ttl60)。这种装饰器叫装饰器工厂写法比基础版多绕一层。另外不想用闭包的话类装饰器也是一种优雅的替代方案。4.1 装饰器工厂给装饰器也装一个参数先想清楚结构外层函数接收装饰器的参数返回一个真正的装饰器真正的装饰器接收函数返回wrapperwrapper内做增强。三层嵌套看着绕但只要按这个套路来就不容易乱import time def retry(times3, delay0.5): def decorator(func): functools.wraps(func) def wrapper(*args, **kwargs): for i in range(times): try: return func(*args, **kwargs) except Exception as e: if i times - 1: raise print(f第{i1}次失败: {e}, {delay}秒后重试) time.sleep(delay) return wrapper return decorator retry(times5, delay1) def fetch_data(): ...这样写和retry也兼容缺点是retry不带括号时retry本身会被当成装饰器直接传入函数导致times参数变成函数对象逻辑就乱了。要兼容两种写法需要加判断但大多数项目里我都是统一要求带括号代码更清晰。某个功能需要重试的次数和退避策略不同这是“给装饰器传参数”最典型的场景。4.2 类装饰器不想写闭包时的另一种选择闭包嵌套多了之后可读性确实一般于是可以用类实现同样的功能。两种风格一种是类接收函数__call__里写增强逻辑另一种是__init__接收参数__call__接收函数。看例子class CallCounter: def __init__(self, func): functools.update_wrapper(self, func) self.func func self.count 0 def __call__(self, *args, **kwargs): self.count 1 print(f{self.func.__name__} 已调用 {self.count} 次) return self.func(*args, **kwargs) CallCounter def greet(name): return fhello {name} greet(a) greet(b)类装饰器一个天然优势是可以在实例上保存状态比如统计调用次数、存缓存结果。注意__init__里我用functools.update_wrapper替代wraps这是为了在类实例上也能保留函数原信息。如果你要给类装饰器传参就把构造函数拆成两层第一层接收参数并返回一个真正的装饰器第二层接收函数。4.3 多个装饰器叠加时的顺序从下往上装饰从上往下执行项目里经常出现一个函数被多个装饰器同时修饰的情况比如先鉴权再记日志再重试。很多人在这里犯迷糊。记住一句话装饰过程从下往上执行过程从上往下。auth_required log_execution retry(times3) def delete_file(path): ...等价于delete_file auth_required(log_execution(retry(times3)(delete_file)))所以retry最先接管原始函数log_execution再包一层auth_required最后包在最外层。执行的时候auth_required先跑通过后才进入log_execution最后才到retry和真实函数。这个顺序直接影响业务如果你想要鉴权失败不记录日志鉴权就必须放最上面如果你想让所有操作都留据可查日志就得放最外层。用表格概括需求目标推荐叠加顺序从上到下原因鉴权优先失败不留日志auth_required 在上面外层没通过进不到内层所有调用都记录日志log_execution 在最上面最外层最先执行、必定被记录重试只对业务异常生效鉴权异常不重试retry 放在业务函数最近处重试只包装原始业务调用顺序放错是我见过最多的“预期之外”的bug排查思路不是去看逻辑而是先列出装饰器栈。5. 拿来即用的实战装饰器日志、计时、重试、缓存原理讲了不少这里直接给四个我在项目里反复用的装饰器。它们都遵循同一个骨架透传参数、透传返回值、保留元信息。5.1 结构化日志装饰器import logging import functools def log_call(loggerNone): if logger is None: logger logging.getLogger(__name__) def decorator(func): functools.wraps(func) def wrapper(*args, **kwargs): logger.info(调用 %s 开始, func.__name__) try: result func(*args, **kwargs) logger.info(调用 %s 成功, func.__name__) return result except Exception as e: logger.exception(调用 %s 异常: %s, func.__name__, e) raise return wrapper return decorator这里有个隐藏坑如果你在装饰器里logger.addHandler(...)那每次给新函数挂装饰器都会往同一个logger上再挂一个处理器最终一条日志被打印多次。我开头说的生产bug就是这么来的。正确做法是Logger初始化归初始化模块装饰器只负责用logger.info打日志绝不注册handler。5.2 高精度计时装饰器def time_it(unitms, loggerNone): def decorator(func): functools.wraps(func) def wrapper(*args, **kwargs): start time.perf_counter() result func(*args, **kwargs) cost time.perf_counter() - start if unit ms: cost_str f{cost * 1000:.2f} ms else: cost_str f{cost:.4f} s if logger: logger.info(%s 耗时 %s, func.__name__, cost_str) else: print(f{func.__name__} 耗时 {cost_str}) return result return wrapper return decorator为什么用time.perf_counter()而不是time.time()因为time.time()返回的是墙上时钟可能被系统时间调整影响在Linux上精度也低perf_counter单调递增且直接使用CPU的高精度计数器适合测量短时间间隔。测慢函数差别不大测微秒级的函数差别会很明显。5.3 重试装饰器我在写数据库连接、外部API请求、临时文件读取时都会挂上重试。生产网络不可能百分百稳定一次超时未必是业务挂了立马重试一次往往就好了。但重试必须有边界无限重试会把小问题拖成大故障。def retry(times3, delay0.5, backoff2, exceptions(Exception,)): times: 最大尝试次数 delay: 初始重试间隔 backoff: 每次重试间隔倍数 exceptions: 触发重试的异常类型 def decorator(func): functools.wraps(func) def wrapper(*args, **kwargs): current_delay delay for i in range(times): try: return func(*args, **kwargs) except exceptions as e: if i times - 1: raise print(f{func.__name__} 第{i1}次失败: {e}, {current_delay}秒后重试) time.sleep(current_delay) current_delay * backoff return wrapper return decorator这里我特意把exceptions做成可配置的因为重试只应该捕获“可能临时恢复”的异常。如果你捕获了Exception这个基类那些因为参数错误、代码bug引起的异常也会被一遍遍重试白白浪费时间还掩盖了真正的错误。5.4 简单缓存装饰器缓存是另一个高频需求。最简单的方式是字典缓存但要小心参数必须可哈希import functools def memoize(func): cache {} functools.wraps(func) def wrapper(*args, **kwargs): # 构造一个可哈希的key key (args, tuple(sorted(kwargs.items()))) if key in cache: return cache[key] result func(*args, **kwargs) cache[key] result return result return wrapper这里有几个注意点kwargs不能直接放进key里因为字典不可哈希所以要转换成tuple(sorted(kwargs.items()))默认参数直接透传给func时args和kwargs可能有两种不同形式比如f(1, 2)和f(1, b2)如果函数定义是def f(a, b)两种调用方式在Python内部会有不同的args/kwargs呈现方式这会导致缓存命中率下降严重时会缓存错误结果。所以最稳妥的做法是用inspect.signature拿到绑定后的完整参数再构造key虽然重一点但不会出错。真正到生产级别建议直接用functools.lru_cache或第三方库它对缓存失效、线程安全、内存上限都有更完整的设计。自己写memoize只适合脚本和原型。6. 避坑实录三个从生产代码里撕下来的教训最后这部分我把自己踩过的真正的坑列出来每一个都曾经让我排查超过两小时希望你能直接跳过。6.1 忘写return导致整个函数全变None前面已经演示过症状了这里讲一下我实际遇到的背景。当时我在给一个批量同步任务加日志装饰器写完没有单元测试直接在命令行跑发现同步结果全成了None。一开始以为是数据库连接问题排查了半天最后打开装饰器源码一眼就看到了问题wrapper里没有返回值。从那以后我的装饰器模板第一行就会写: return func(*args, **kwargs)但凡中间有业务逻辑也一定在最前面声明result func(...)保证逻辑不会让我忘了传递。如果你的装饰器不准备接收返回值那也要明确写成result func(...)然后return None把意图表达清楚。6.2 忘写functools.wraps导致inspect签名全乱有个项目在接口文档自动生成环节依赖inspect.signature提取参数某天几个接口的参数列表突然变成(*args, **kwargs)文档全废了。查来查去新加的一个装饰器没挂wraps把真实签名藏起来了。更隐蔽的是某些测试框架、Mock工具也会基于__wrapped__去找原始函数不写wraps会让它们失效。凡是我负责的代码装饰器内部第一行一定是functools.wraps(func)没有任何例外。6.3 类方法装饰器self被吞掉的问题如果你给类方法写装饰器直接在wrapper里调用func没走实例绑定就会踩到一个经典坑def require_perm(permission): def decorator(func): functools.wraps(func) def wrapper(*args, **kwargs): # 这里如果硬编码取 args[0] 当 self 用会有问题 return func(*args, **kwargs) # 正常透传才对 return wrapper return decorator只要你坚持用*args, **kwargs原样透传Python的方法绑定机制会正常工作instance.method(...)被调用时实例会被自动塞进args[0]然后原样传给func。问题出在一些自作聪明的装饰器里自己拆了args重新组装漏掉了self或cls于是报missing 1 required positional argument: self。我的建议是装饰类方法时不要试图解析args一律全量透传。如果确实需要知道第一个参数是谁用inspect.getfullargspec判断是不是self或cls再决定怎么处理不要硬编码。另一个和类相关的坑装饰器直接写在staticmethod或classmethod下面时顺序要特别小心。staticmethod返回的是一个描述器对象和普通函数行为不同装饰顺序错了会让静态方法变成一个普通函数调用时莫名多出第一个参数。我的经验是自定义装饰器尽量放在staticmethod/classmethod的“下面”让它们先作用于原始函数再由staticmethod/classmethod包装这样能少踩很多坑。最后一个经验分享装饰器虽然看起来很酷但不要在项目里堆砌超过两层的装饰器链更不要写一个“万能装饰器”试图同时处理日志、缓存、鉴权、重试。每增加一层排查问题的复杂度就指数上升。我后来更喜欢的做法是把装饰器当成注册表和使用者之间的协议只做一件事做干净。这样代码读起来像洋葱一样层次分明出问题也能按层剥开而不是一团乱麻。把这篇文章里的模板粘进你的工具库从最简单的一两个开始用比一次性背下所有概念有效得多。

相关新闻

DeepSeek Harness桌面端实战:API Key配置、插件管理与离线部署避坑指南

DeepSeek Harness桌面端实战:API Key配置、插件管理与离线部署避坑指南

1. 从命令行到桌面窗口:DSH 到底解决了谁的痛点DeepSeek Harness 这个项目在圈子里其实已经不算新面孔了,但很长一段时间里,它的使用门槛都卡在“你得先会折腾命令行”这一步。官方桌面端出来之后,情况变了——不用再对着终端敲一…

2026/10/5 4:46:39 阅读更多 →
不用大模型也能做虚假新闻检测:MLP加TF-IDF全流程实战

不用大模型也能做虚假新闻检测:MLP加TF-IDF全流程实战

简介:基于Python和MLP实现的互联网虚假新闻检测器,是一个涵盖数据预处理、模型训练、参数调优与预测输出的完整机器学习项目,主要面向自然语言处理初学者、计算机专业学生及需快速搭建文本分类模型的开发者,适用于课程设计、毕业设…

2026/10/5 4:46:39 阅读更多 →
AI Native 团队开发落地手册:从意图契约到多 Agent 协作

AI Native 团队开发落地手册:从意图契约到多 Agent 协作

1. 从“人写代码”到“人管意图”:AI Native 团队到底在改什么先说一个我观察到的现象。很多团队嘴上喊着“我们要做 AI Native”,实际干的事只是给每个人发了个 AI 编程助手的账号,然后继续用原来的方式拆需求、写文档、排期、Code Review。…

2026/10/5 4:46:38 阅读更多 →

最新新闻

IT6801显示控制器驱动开发:Datasheet、寄存器与移植实战

IT6801显示控制器驱动开发:Datasheet、寄存器与移植实战

简介:面向ITE6801/IT6801显示控制器的全套资料,主要服务嵌入式显示驱动开发工程师与C/C底层编程人员,重点解决屏幕初始化、寄存器配置、时序调试与驱动移植问题。压缩包共15个文件、约10.37MB,主体为9份PDF数据手册和编程指南&…

2026/10/5 5:20:52 阅读更多 →
Java工程师转型AI Agent实战:从LangChain4j到生产级并发与RAG落地

Java工程师转型AI Agent实战:从LangChain4j到生产级并发与RAG落地

1. Java 工程师转型 AI Agent 的底层逻辑与路径选择1.1 为什么 Java 工程师转 AI Agent 有天然优势很多 Java 工程师一提到 AI Agent,第一反应是“这是 Python 的天下,我是不是得从头学一门语言”。我刚开始接触这个方向时也有同样的焦虑,但实…

2026/10/5 5:20:52 阅读更多 →
二维数组子数组筛选全解析:C#与C语言实现及边界避坑

二维数组子数组筛选全解析:C#与C语言实现及边界避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 5:20:52 阅读更多 →
一张图加一段音频生成数字人:从原理到实操的完整指南

一张图加一段音频生成数字人:从原理到实操的完整指南

数字人这个方向我前前后后折腾了快两年,从最早用现成SaaS工具套模板,到后来自己搭管线跑模型,踩过的坑能写满一个笔记本。最近半年,圈子里讨论最多的就是“一张图加一段音频直接出片”的方案——不需要3D建模,不需要动…

2026/10/5 5:20:51 阅读更多 →
单文件HTML跨年祝福页制作指南:倒计时、烟花与部署

单文件HTML跨年祝福页制作指南:倒计时、烟花与部署

简介:HTML跨年主题网页源码包,面向网页设计与前端初学者,可用于制作春节、跨年庆祝页面。包内包含完整的前端文件,涵盖烟花特效、新年倒计时、祝福弹窗、背景音乐切换及响应式布局等常见节日页面功能,适合直接运行查看…

2026/10/5 5:20:51 阅读更多 →
航班飞行网图分析实战:基于Spark GraphX的图计算应用

航班飞行网图分析实战:基于Spark GraphX的图计算应用

做航班数据分析这几年,我越来越觉得把航班数据当普通关系表来算,其实有点浪费。航线的本质就是一张巨大的图——机场是顶点,航班是边,旅客中转天然就是在图上做路径遍历。刚接触 Spark 的时候我也习惯性用 DataFrame 做 join 和 g…

2026/10/5 5:19:51 阅读更多 →

日新闻

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:22 阅读更多 →
AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

1. 从“plugins”这个词说起:它到底在解决什么问题如果你最近在折腾 AI 编程工具,尤其是 Cursor、Codex CLI、Claude Code 这类带 CLI 的编辑器或命令行助手,那你大概率绕不开一个词——plugins。这个词本身不新鲜,从浏览器到 IDE…

2026/10/5 0:00:23 阅读更多 →
第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:23 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 5:06:42 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 1:10:22 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 3:06:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 20:14:29 阅读更多 →