当前位置: 首页 > article >正文

深刻思考Python 装饰器——不输Java Aop的切面编程利器

先说结论java 注解能实现的功能python 的装饰器绝大部分都是可以胜任的装饰器更像 Java 中注解加上Aop两者的组合python 是一门极简的语言语言简洁学习起来也是相当轻松的但是依然有一些高级技巧例如装饰器协程并发会让人感觉困惑失望与沮丧本文将重点讲解 python装饰器的使用使用常用的例子让我们更直观的看到装饰器的强大表达能力最后也给出了编写装饰器常见的工具。熟悉 java的同学一定熟悉注解的使用借助于注解可以定义元数据配置我们常常有这种感受“只要加上这个注解我的组件就会被注册进去”“只要加上这个注解就会添加事务控制”也会困惑“为什么加了这个注解依然没有生效?” python 没有提供像Java似的注解但是提供了相比注解表达能力更加强大的装饰器。例如 web框架 Flask 中的route errorhandler及 python 自带的 propertystaticmethod等。 实际上java 注解能实现的功能python 的装饰器绝大部分都是可以胜任的装饰器更像 Java 中注解加上Aop两者的组合 这个结论最后我们会重点讨论先按下不表。现在首先以日志打印的简单例子初步讲解一下装饰器的使用1.0 装饰器的简单例子def log(func): #1 def func_dec(*args, **kwargs): #2 r func(*args, **kwargs) #3 print(didiyun execute done:%s % func.__name__) return r return func_dec log #4 def test_dec(size, length, kyNone): print didiyun execute test_dec param:%s, %s, %s % (size, length, ky) def test(): test_dec(kyyuhaiqiang, length3, size1) 输出结果可以看到装饰器的装饰逻辑已正确被执行 didiyun execute test_dec param:1, 3, yuhaiqiang didiyun execute done:test_dec 1 定义 log 装饰器输入参数func是需要被装饰的函数本例中输出打印是 test_dec 2 定义一个装饰函数参数类型包括变长的位置参数和名字参数适应被装饰函数不同的参数组合这种写法可以代表任意参数组合 3 执行实际的函数func_dec 注意处理返回值不要吞掉被装饰函数的返回值 4 在被装饰函数上添加装饰器注意此处不要加()后面会解释具体原因了解该原因就能完全了解装饰器的小九九装饰器可以在函数外层添加额外的功能装饰原函数 本例的装饰器只是在函数外层打印一行日志实现的是非常简单的功能实际中装饰器并不是仅仅打印日志的雕虫小技还能实现其他更有用的功能2.使用装饰器巧用文件锁2.1 使用 fcntl 实现文件锁class Lock: def __init__(self, filename, blockTrue): #block 参数为 true代表阻塞式获取。 False为非阻塞如果获取不到立刻返回 false self.filename filename self.block block self.handle open(filename, w) def acquire(self): if not self.block: try: fcntl.flock(self.handle, fcntl.LOCK_EX | fcntl.LOCK_NB) return True except: return False else: fcntl.flock(self.handle, fcntl.LOCK_EX) return True def release(self): fcntl.flock(self.handle, fcntl.LOCK_UN) self.handle.close()借助于 fcntl 库 我们已经实现文件锁感兴趣的读者可以深入了解一下 fcntl 库下面我们以文件锁为例介绍一下装饰器很实用很常见的一些功能。2.2 定义文件锁装饰器def file_lock(lock_name, blockTrue): #1 def wrapper(func): def f(*args, **kwargs): name lock_name lock Lock(name, block) acquire lock.acquire() if not acquire: print(failed to acquire lock:%s,now ignore % name) return #2 print(acquire process lock:%s % name) try: return func(*args, **kwargs) finally: lock.release() #3 print(release process lock:%s % name) return f return wrapper file_lock(name/var/local/file, blockTrue) #4 def get_length(): pass get_length() 输出 #5 acquire process lock:/var/local/file execute test_dec param:1 release process lock:/var/local/file定义 file_lock 装饰器接受两个参数 lock_name:锁路径 block: 是否阻塞式的获取该处在获取锁失败时仅仅返回了 None 调用方无法 明确知道None 是 get_length 的返回值还是获取锁失败实际上应该抛出一个异常交给上游调用方去处理 获取锁操作失败的异常try finally 保证锁一定可以被释放在使用文件锁的时候还需要提供锁的值能否提供默认值呢?只对该实例方法加锁读者可以考虑一下如何实现。此外细心地读者能比较出来file_lock装饰器添加了括号()但是两者的区别可不仅仅因为一个有参数一个无参后一节解释下装饰器的语法糖本质实际在项目中使用时经常会遇到文件锁的问题 在项目调试阶段 由于经常需要手动终止强杀程序 这样会导致文件锁没有被正确清理读者可以考虑将文件锁指定在一个固定的目录 每次进程启动时检测是否有同路径进程如果没有 可以清理该目录如果存在同路径进程说明现在有并发执行不清理该目录。 如果没有清理功能可能会导致永远无法获取到锁。 如果不实际使用以上代码实现文件锁可以忽略该问题不影响理解装饰器。 感兴趣的读者可以试试希望能提出更好的文件锁方案使用文件锁之后调用该方法必须先获取到锁否则只能先阻塞。 因此实际的处理方法不需要处理同步逻辑 只需要一行装饰器 就额外扩展了同步功能 通过异常控制还能保证文件锁一定可以被释放 避免文件锁泄露 通过装饰器我们还可以实现很多其他有用的功能但是文件锁装饰器的实现已经相比日志装饰器复杂了 仔细观察 它已经 嵌套了 三层函数后续我们会优化这个问题。2.3 解释1.0 的疑问何时使用装饰器需要添加 括号()在1.0 日志装饰器的例子我们留下了一个疑问为什么 log 装饰器不需要加() 而文件锁装饰器的使用却加了()回到1.0 的装饰器实现假如我们不使用 log 的方式使用如下方式呢?能不能实现相同的逻辑?log def foo(): pass foo() # 相当于 log(foo)()log(func) 返回装饰函数最后的括号代表执行 foo log(foo) # 就是装饰器语法糖帮我们做的log 方法接受的参数是 func 自然当手动显式 调用 log 装饰 foo 函数时 丝毫不影响实现装饰的功能. 但是显得我们很啰嗦很蠢 幸福的是 python提供了装饰器的语法糖 使用该语法糖就好像我们手动执行装饰一样。 但是如果我们加上括号代表什么意思呢? log() 的写法 不就相当于调用了 log 函数但是又不给其传参?实际 python 解释器也是这么抗议 我们的。但是为什么文件锁又加上了括号呢?答案是装饰器有时候需要一些额外的参数例如 Flask 中我们常用的 route我们需要告诉 Flask 如何 将url映射到具体的 handler 自然需要告诉 route 需要绑定的 url 是什么 和 spring 的RequestMapping作用类似当装饰器加上参数之后 惊讶的发现装饰器更像是三层函数了… 可理解性已经极差了 但是一旦理解之后我们会发现三层函数是原因的不妨这样理解 当装饰器没有参数 就像log 装饰器该装饰器接受参数为 func 我们称其为两层装饰器 以上我们已经分析了它的的原理foo log(foo). 装饰器的标记等于告诉 python解释器 “你把下一行的函数作为参数传给该装饰器然后把返回值赋值给该函数” 相当于执行 foo log(foo)当我们调用 foo() 相当于是调用 log(foo)()。对于带参数的装饰器file_lock(nameblock) 我们分成两个阶段理解回顾一下 file_lock 的三层函数实现我们在第二层定义了一个 wrapper 函数该函数接受了一个 func 参数,随后我们在 file_lock的最后将其return 我们可以这样认为file_lock(name/var/local/test,blockTrue) def test() pass wrapper file_lock(name, block) #第一阶段 test wrapper(test) #第二阶段第一阶段执行了最外层的函数file_lock 返回了 wrapper。 第二阶段使用 wrapper 装饰 test 第二阶段我们已经熟悉理解了。实际上 只是第一阶段是多执行的。 由于我们多给它加了一个括号 python 解释器自然会去执行该函数 该函数返回另一个装饰函数 这样就到了第二阶段。python 解释器希望我们这样去理解否则三层函数的写法很让人崩溃。后续我们继续探索装饰器能不能实现相同的功能但是能摆脱编写三层函数的噩梦。以上分析了带参数和不带参数的装饰器的区别及如何在心里去理解与接受这种写法 python 通过语法糖 函数之上的装饰器定义 代替蠢笨的手动装饰调用。 我们可以实现复杂的装饰器 但却能提供极其优雅的使用方式给调用方 还是 让人鼓舞的事实上 python的框架中大量的使用了装饰器。也说明了装饰器的强大与优雅。3.python 装饰器方法的执行时机与顺序python 是解释执行的语言我们做一个小实验以上例子先定义 log 装饰器而后再使用 log装饰器如果置换一下顺序log(say some thing) def test_dec(size length, kyNone): print execute test_dec param:%s, %s, %s % (size, length, ky) def log(infoNone): def wrapper(func): def func_dec(*args, **kwargs): r func(*args, **kwargs) print(execute done:%s % func.__name__) return r return func_dec return wrapper毫无疑问这样会报语法错误 python是 从python文件从上到下执行解释执行 只有已经定义log 才能使用它。在python 中函数是一等公民 函数也是对象在定义函数时也就是在声明一个函数对象def foo(): passdef foo()就是在声明一个函数对象 foo 即是该函数对象的引用 我们可以额外定义该对象的属性 通过dir(foo) 查看一下该函数对象有哪些属性其实是和类实例对象没有区别的以上提过 test 被 log装饰 后 test() 等同于log(test)() python 装饰器解释执行完 log def test()等同于testlog(test) 此时 test引用的函数对象是 log装饰后的函数对象log def test(): pass testlog(test)3.2 装饰器的执行顺序实际开发中我们经常会遇到使用多个装饰器如果读者理解了3.0及以上的函数对象的概念其实应能能猜出来装饰器的装饰顺序自然是从上往下执行的foo a(b(c(foo))) 但是实际的代码执行顺序是 c-b-aa b c def foo() pass以上我们使用日志装饰器和文件锁装饰器介绍了装饰器的使用并且讨论了带参数及不带参数装饰器的区别。其中三层函数的定义方式可读性非常差在下一节将重点讨论如何使用类实现装饰器简化三层装饰器的逻辑减少相似代码的编写4. 装饰器类的设计在本节中我们重点优化三层装饰器的编写除此之外笔者在实际开发中还发现了其他常见的需求例如暂存装饰器的参数。 期望通过被装饰函数找到装饰器参数 笔者在自动化测试中就使用装饰器定义测试 case 需要在 case 中配置元数据信息在实际的执行引擎部分访问该元数据信息。就是将元数据信息放到函数对象中注册被装饰函数对象。 例如某些 web 框架注册 handler 需要在装饰器中实现某些注册逻辑从以上三点出发可以看到装饰器的逻辑有某些通用的部分然而以上装饰器的例子都是通过函数实现的 但函数在内部状态 继承等方面明显不如类所以我们尝试使用类实现装饰器。并尝试实现一个通用的装饰基类4.1 思路python 提供了很多奇异方法所谓的奇异方法是指只要你实现了这个方法就可以使用 python 的某些工具方法例如实现__ len__ 方法可以使用 len() 获取长度实现__ iter__ 可以使用 iter方法返回一个迭代器其他方法还有 “__eq__”“__ne__” “__next__” 等。 其中当实现__ call__ 方法时 类可以被当做一个函数使用例如以下示例class FuncClass(object): def __call__(self): print(didiyun) F FuncClass() F() didiyun是否也可以使用 python 的这个特性实现装饰器呢?答案是可以的让我们来实现一个装饰基类 解决以上的痛点class BaseDecorator(object): def __call__(self *_, **kwargs): #1 return self.do_call(**kwargs) #2 def do_call(self, *_, **decorator_kwargs): def wrapper(func): wrapper.__explained False wraps(func) #3 def _wrap(*args, **kwargs): if not wrapper.__explained: #4 self._add_dict(func, decorator_kwargs) wrapper.__explained True return self.invoke(func, *args, **kwargs) #5 self._add_dict(_wrap, decorator_kwargs) _wrap self.wrapper(_wrap) #6 return _wrap return wrapper def wrapper(self, wrapper): return wrapper def _add_dict(self, func, decorator_kwargs): for k, v in decorator_kwargs.items(): func.__dict__[k] v def invoke(self, func, *args, **kwargs): return func(*args, **kwargs) BaseDecorator实现的并不是具体的某个装饰器逻辑,它可以作为装饰器类的基类以上我们曾分析编写装饰器通用的需求已经痛点。以下先具体讲解这个类的实现而后在讨论如何使用 1. __call__ 函数签名*_ 代表忽略变长的位置参数只接受命名参数。实际的装饰器中一般都是使用命名参数.代码可读性高 2. __call__ 本身的实现逻辑委托给了 do_call 方法主要是考虑 BaseDecorator 作为装饰基类需要提供某些工具方法及可扩展方法但是__ call__ 方法本身无法被继承所以我们退而求次将工具方法封装在自定义方法中子类还是需要重新 实现__ call__ 并调用 do_call 方法 do_call 方法的签名和__ call__ 相同 3. functools提供了 wraps 装饰器 以上我们分析过python是使用装饰后的函数对象替换之前的函数对象达到装饰的效果 可能有人会有疑问如果 之前的函数对象有一些自定义属性呢? 装饰后的新函数会不会丢掉答案是肯定的 我们可以访问之前的函数对象给其设置属性 这些属性会被存储在 对象的__ dict__ 字典中 而wraps 装饰器会把原函数的__ dict__拷贝到新的装饰后的函数对象中 因此 wraps 装饰后就不会丢掉原有的属性 而不使用则一定会丢掉。 感兴趣的读者可以点开 wraps 装饰器看一下具体实现逻辑 4. 在本节开始我们提出装饰器的通用需求其中之一是需要将装饰器的参数存放到被装饰的函数中_add_dict方法便是将装饰器参数设置到原函数以及装饰后的函数中 5. invoke 负责实现具体的装饰逻辑例如日志装饰器仅仅是打印日志那么该方法实现就是打印日志以及调用原函数。 文件锁装饰器则需要先获取锁后在执行原函数具体的装饰逻辑在该方法中实现 具体的装饰器子类应该重写该方法。下一节我们继承该BaseDecorator重写以上的日志及文件锁装饰器 6. invoke 方法是装饰函数调用时被触发的 而 wrapper 方法只会被触发一次当 python 解释器执行到log时会执行该装饰器的wrapper 方法。相当于函数被定义的时候执行了 wrapper方法在该方法内可以实现某些注册功能。将函数和某些键值映射起来放到字典中例如 web 框架的 url和handler映射 关系的注册BaseDecorator 抽出来了 invokewrapper 目的是让子类装饰器可以在这两个维度上扩展分别实现装饰及某些注册逻辑在下一节我们尝试重写日志及文件锁装饰器更直观的感受BaseDeceator 给我们带来的便利4.2 重写日志及文件锁装饰器class _log(BaseDec): def invoke(self, func, *args, **kwargs): #1 print(execute done:%s, %s % (func.__name__,func.desc) ) #2 return func(*args, **kwargs) def __call__(self, desc): return self.do_call(descdesc) log _log() #2 1. invoke方法中包括原函数以及原函数的输入参数该输入参数不是装饰器的参数信息 2. 通过 func 可以访问到装饰器中定义的 desc 参数信息 3. 创建装饰器实例 便可以像之前一样使用 log需要注意的是该装饰类变成单例 在定义装饰逻辑的时候不要轻易在 self 中储存变量通过重写日志装饰器 可以看到已经摆脱了三层函数的噩梦 成功的分离了装饰器的基本代码以及装饰逻辑代码我们可以更加聚焦于装饰逻辑的核心代码编写同时可以通过原函数访问装饰器中输入的参数例如可以访问到日志装饰器的 desc以下我们再重写文件锁装饰器class _file_lock(BaseDec): def invoke(self func, *args, **kwargs): name func.name #1 lk Lock(name, True) acquire lk.acquire() if not acquire: print(failed to acquire lock:%s,now ignore % name) return print(acquire process lock:%s % name) try: return func(*args, **kwargs) finally: lk.release() print(release process lock:%s % name) def __call__(self, name, blockTrue): return self.do_call(namename, blockblock) #2 file_lock _file_lock() #3 1. 可以通过 func 访问到装饰器中定义的 name 参数 2. 把参数传给 do_call 委托执行 3. 创建文件锁实例,其他位置就可以使用file_lock了使用新的装饰基类后 编写新的装饰器子类是非常轻松方便的事情 不需要再蹑手蹑脚的定义复杂的三层函数 不需要重复的设置装饰器参数 如果我们在项目中大量使用装饰器 不妨使用装饰基类 统一常见的功能需求。装饰器的更多用法还需要读者去发掘但是熟悉 java 的同学一定熟悉 aop 的理念 笔者深受 java 折磨多年 对 aop也几分偏爱 在我看来 python 的装饰器是 java 中的注解加 aop 的结合。下一节我们横向对比一下 java 注解与 python 装饰器的相似点 论证文章开头我们留下的一个论点5.对比 Java 的注解之所以对比 java 注解主要是笔者想从 java 的某些用法得到某些借鉴与参考 以便于我们应用到 python 中通过两种语言的对比可以让我们更深刻的理解语言设计者添加该特性的初衷以便更好的使用该特性。 更重要的是让我们面对不同语言的异同 有更大的包容性 站在欣赏的角度去对比思考对于我们快速掌握新的语言十分有益。本节绝不是为了争吵两种语言的优劣 更不想挑起语言的战争装饰器和注解最直观的相似点可能就是艾特符号了 python 使用相同的符号 对于 java 程序员是一种关照。 因为 java 程序员对于注解有一种特殊的迷恋 第三方框架就是使用眼花缭乱的注解 帮助 java 程序员实现一个个神奇的功能。而装饰器也是可以胜任的java 的注解本身只是一种元数据配置在没有注解之前 如果实现相同的元数据配置只能依赖于 xml 配置 有了注解之后我们可以把元数据配置和代码放到一起这样更加直观 也更便于修改至于某些人说 xml配置 可以省却编译打包 其实在笔者经历的项目中不论是改代码还是改配置都是需要重新走发布流程 严禁直接修改配置重启程序(除极特殊情况)。注解和注解解释器是密不可分的定义注解之后首先就应该想到如何定义解释器读取注解上的元数据配置使用该元数据配置做什么。最常见的是使用方式是使用注解注册某些组件开启某项功能例如 spring 中使用 Component注册 bean使用 RequestMapping 注册 web url 映射 junit 使用 Test 注册测试 Case Spring boot 中使用 EnableXXX 开启某些扩展功能等等注解解释器首先需要获取到Class 对象使用反射获取到注解中的元数据配置然后实现注册 开关逻辑。 以上在我们实现的解释器基类中我们也实现了类似的功能我们把装饰器的参数存放到具体的函数对象中 实际等同于注解的元数据配置 读者也可以扩展 添加一个标记 标记该函数对象确实被某装饰器装饰过。 这样便能像 java 一样轻松的实现某些注册或者开关功能。除此之外注解作为元数据配置可以作为 aop 的切面这也是注解被广泛使用的原因 注解可以配置在类属性方法之上 “注册” 功能一般是配置在类上 如果使用注解切面需要将注解配置在方法之上。以下列出使用注解 aop 可以实现的功能1. 异常拦截 在使用该注解的函数切面上将异常拦截住可以做一些通用的功能例如异常上报异常兜底异常忽略等 2. 权限控制 日志记录。 可以控制注解方法的切面的用户访问权限也可以记录用户操作 3. 自动重试 异步处理。如果我们希望异步调用某方法或者某些需要异常重试的方法可以使用注解定义切面 添加异步或重试处理注解提供了非常灵活的切面定义方式以上三种只是常见的使用方式当注解定义了切面 aop 会替换被代理的类 添加某些代理逻辑 抛开底层实现原理 实际上aop这种机制和 python 的装饰器区别并不是很大 设计模式中装饰器和代理模式本身就非常相似 以上注解可以实现的功能 python 的装饰器都是可以一一实现的。在函数被定义的时刻装饰器就已经生效了 而 aop也是通过编译期或者运行期在实际调用之前代理。python 的装饰器本身也是一个函数它通过语法糖的方式帮我们实现了装饰而 静态类型的java 选择了动态修改字节码编译器织入等更加复杂的技术实现了类似的功能。 不同的底层实现 并不能影响在使用方式及场景上互相借鉴。 所以笔者还是认为装饰器更像 java 注解 aop 的组合。 这样对比 对于java 程序可能更容易理解更好的使用装饰器。最后五阳一直在关注 AI方向我分享一个对抗AI“一本正经胡说八道”的个人技巧不要只依赖一个模型。我现在遇到拿不准的信息会把同一个问题同时扔给2-3个AI比如千问DeepSeek看它们答案的交集。这比单纯选哪个模型更靠谱。想省事的话可以用这个聚合工具一次搞定AIChatProxy https://aichatproxy.com

相关文章:

深刻思考Python 装饰器——不输Java Aop的切面编程利器

先说结论 java 注解能实现的功能,python 的装饰器绝大部分都是可以胜任的,装饰器更像 Java 中注解加上Aop两者的组合 python 是一门极简的语言,语言简洁学习起来也是相当轻松的,但是依然有一些高级技巧,例如装饰器&am…...

TinyPICO Helper库:嵌入式胶水层设计与低功耗实践

1. TinyPICO Helper Library 深度技术解析TinyPICO 是一款基于 ESP32-PICO-D4 封装的超紧凑型 Wi-Fi 微控制器开发板,其物理尺寸仅为 21mm 21mm,却集成了 Wi-Fi、蓝牙双模无线能力、板载 APA102 LED(DotStar)、锂电充电管理与电压…...

树莓派5实战:NCNN部署YOLOv8n实现实时视频目标检测

1. 为什么选择树莓派5部署YOLOv8n? 树莓派5作为最新的单板计算机,性能相比前代提升了2-3倍,特别适合边缘计算场景。我在实际测试中发现,其搭载的Cortex-A76四核处理器和VideoCore VII GPU,在处理轻量级AI模型时表现突出…...

智能助盲新方案:CYBER-VISION零号协议实战案例分享

智能助盲新方案:CYBER-VISION零号协议实战案例分享 1. 技术背景与项目意义 视障人士在日常生活中面临着诸多挑战,其中最为关键的是环境感知与导航问题。传统助盲设备如白手杖虽然实用,但在复杂环境中的信息反馈有限。CYBER-VISION零号协议应…...

VideoAgentTrek-ScreenFilter惊艳时刻:复杂游戏界面UI元素的精准识别与艺术化处理

VideoAgentTrek-ScreenFilter惊艳时刻:复杂游戏界面UI元素的精准识别与艺术化处理 不知道你有没有过这样的经历?辛辛苦苦打了一局精彩游戏,想录下来分享给朋友,结果回放时发现,整个画面被各种血条、地图、技能图标和聊…...

买UPS 电源别懵!分类全解析看懂这几种,姐姐带你避坑! 必看

哈喽,各位老板、同行、还有刚入行的小伙伴们,我是你们卖 UPS 电源的姐姐!平时经常有客户问我:“姐姐,UPS 到底怎么分啊?我看有不同尺寸,到底我该选哪种?”今天姐姐就用大白话&#x…...

数据治理-Doris-别名函数和存储过程

目的 记录使用Doris进行数据治理过程中的经验技巧 别名函数 数据治理-SQL生产过程中,需要将大量常用到的数据加工逻辑简化为单个函数,以精简SQL语句,提升可读性和可维护性。 Doris中创建函数的方法有两种: 1、UDF方式:…...

Claude Code 的 CLAUDE.md 与技能

“到底什么信息该写进 CLAUDE.md,什么信息又该写进 Skills?”说实话,这不是一个小问题。恰恰相反,如果你开始认真、长期、规模化地使用 Claude Code,这几乎就是最关键的架构决策之一。很多团队前期觉得无所谓&#xff…...

逆向工程OWASP ZAP:从代码到架构的软件工程实践

一、写在前面在软件工程课程中,老师反复强调一个观点:安全漏洞的本质往往是软件工程实践的系统性失败。也就是说,很多漏洞的产生,根源不在于某个具体的代码错误,而在于整个软件的设计、架构、开发流程中存在系统性问题…...

PCB设计效率翻倍:用CATIA批量导出元器件2D轮廓的隐藏技巧

PCB设计效率革命:CATIA批量导出2D轮廓的工业级解决方案 在高速迭代的电子产品开发周期中,PCB工程师常常需要处理数百个器件的3D模型转换工作。传统单器件操作模式不仅耗时费力,更可能成为项目进度的瓶颈。CATIA作为航空与汽车行业的主流CAD工…...

自动开窗器市场剖析:2026 - 2032年复合年增长率(CAGR)为6.0%

据恒州诚思调研统计,2025年全球自动开窗器收入规模约达19.73亿元,预计到2032年,这一数字将接近29.62亿元,2026 - 2032年复合年增长率(CAGR)为6.0%。在建筑智能化与节能需求日益凸显的当下,自动开…...

小波阈值去噪在生物医学信号处理中的应用:从原理到实践

小波阈值去噪在生物医学信号处理中的应用:从原理到实践 生物医学信号处理领域正面临前所未有的挑战与机遇。ECG、EEG等生理信号中往往混杂着肌电干扰、工频噪声和基线漂移等多种噪声,传统滤波方法难以在保留关键病理特征的同时有效抑制噪声。小波阈值去噪…...

基于生成对抗网络与Transformer注意力机制的股票价格预测系统

基于生成对抗网络与Transformer注意力机制的股票价格预测系统 1. 引言与相关工作 1.1 传统时序预测的局限性 股票价格预测是典型的非线性、高噪声、非平稳时间序列问题。传统的ARIMA、GARCH等统计模型难以捕捉复杂的非线性模式。LSTM虽然在一定程度上解决了长序列依赖,但其…...

工厂型卖家的商业模式、选品逻辑与实操打法

一:工厂卖家模式选择转型前,我们首先要想清楚四个问题:我们在做什么?我们有什么?我们跟谁做?我们怎么做?这四个问题直接决定了后续的投入上限和天花板。很多工厂型卖家都有个误区,觉…...

F3U源码STM32仿三菱PLC底层实现

项目概述 这个项目实现了基于STM32的仿三菱PLC底层系统,提供了类似三菱FX系列PLC的功能,包括梯形图编程、I/O处理、通信协议等核心功能。 系统架构 ----------------------- | 应用层 | | (梯形图程序/ST语言) | -----------------…...

强化学习数据长啥样?手把手教你用ViTables“透视”d4rl的CartPole/Hopper数据集

强化学习数据解剖指南:用ViTables透视d4rl数据集的内在逻辑 当你第一次打开一个强化学习数据集时,那种面对未知结构的茫然感我深有体会。去年在研究Hopper环境时,我花了整整三天才搞明白数据集里那些数字究竟代表什么。直到发现了ViTables这个…...

AI Agent团队架构演进:从1个扩到8个再砍回4个

标题 **从 1 到 8 再到 4:我的 AI Agent 团队架构演进实录**标签 AI Agent LLM 自动化 系统架构 工程实践封面图建议 一张简洁的架构图(1→8→4 的演进过程)---正文> 这是一篇关于真实踩坑的文章。不是教程,是复盘。背景三个月…...

Gephi图形导出PDF不显示节点标签

Gephi图形导出SVG、PNG均正常,但是导出PDF不显示节点标签,此时只需将节点标签字体设为英文字体即可...

FUTURE POLICE语音模型卷积神经网络前端处理优化:提升噪声环境识别率

FUTURE POLICE语音模型卷积神经网络前端处理优化:提升噪声环境识别率 你有没有试过在嘈杂的街道上对着手机说话,结果语音助手完全听不懂你在说什么?或者工厂里的工人想用语音指令操作设备,却因为机器轰鸣声而频频失败&#xff1f…...

DeepChat在Visual Studio中的智能开发插件

DeepChat在Visual Studio中的智能开发插件 1. 引言 作为一名开发者,你是否曾经在编码时遇到过这样的困扰:写了一半的代码突然卡壳,不知道下一步该怎么实现;或者遇到一个奇怪的错误提示,花了半天时间也找不到解决方案…...

Hackadmin-RTB-2 WP记录

信息搜集永远的第一步不知道666是个什么东西,可以访问一下无法访问dirsearch扫下目录依次访问一下看看有没有交互点开始找漏洞扫一下有没有注入点没扫出来并且扫phpmyadmin也没有扫出来虽然目前的两个页面可交互的地方都没有办法通过sql注入进行脱库,但是…...

挖到宝了!沃尔沃项目EPLAN工程模板全集,10套超值大放送

超值大型10套 EPLAN 工程:沃尔沃项目模板全集,高效设计一触即达 超大型I EPLAN电气工程图纸I 沃尔沃项目EPLAN图纸模板合集 另外:再10套PDF图纸(已打包一起) 1. 参考车企设备通用标准图纸层级分类(高层代号分类)&#…...

一键部署QWEN-AUDIO:赛博可视化界面,让文字秒变超自然语音

一键部署QWEN-AUDIO:赛博可视化界面,让文字秒变超自然语音 1. 引言:语音合成的未来已来 想象一下,你正在为一个重要项目准备演示文稿,需要为每张幻灯片配上专业解说。传统方法要么自己录音,要么花钱请配音…...

COCO2017数据集实战:如何利用官方API统计各类别的图片和标注框数量

COCO2017数据集深度解析:用Python API实现类别统计与可视化分析 计算机视觉领域的研究者和开发者们,一定对COCO数据集不陌生。作为目前最流行的目标检测基准数据集之一,COCO2017以其丰富的标注类别和高质量的图像数据,成为算法开发…...

告别出图焦虑!用Cadence Allegro导出Gerber文件的5个关键检查点与高效技巧

告别出图焦虑!Cadence Allegro导出Gerber文件的5个关键检查点与高效技巧 作为一名PCB工程师,你是否曾在深夜赶项目时,因为Gerber文件导出错误而被迫返工?或是面对复杂的多层板设计,对导出流程的每一步都如履薄冰&#…...

Prompt Engineering入门指南:从入门到精通的实战笔记

👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕人工智能这个话题展开,希望能为你带来一些启…...

【首发实测】RTX 4060 成功捕获 Karpathy 的“自动科研助手”!5分钟跑完 3500 万 Token,进化开始!

【首发实测】RTX 4060 成功捕获 Karpathy 的“自动科研助手”!5分钟跑完 3500 万 Token,进化开始! Baseline 跑通,坐标 4060 笔记本 经过一波三折的环境折腾(解决 Windows 不支持 Triton、修改镜像源、手动魔改 train.py),我终于在我的 RTX 4060 Laptop 上成功跑通了 …...

Wireshark实战:如何从流量包中揪出黑客的蛛丝马迹(附真实案例解析)

Wireshark实战:从流量包中还原黑客攻击全链条 网络安全的世界里,数据包就像犯罪现场的指纹。作为网络取证领域的瑞士军刀,Wireshark能让我们像侦探一样,从海量流量中抽丝剥茧还原攻击过程。今天我们就通过一个真实案例&#xff0c…...

从PyInstaller到NSIS:一个全栈项目打包避坑指南当Vue遇上FastAPI,如何优雅地打包成Windows安装程序

从PyInstaller到NSIS:一个全栈项目打包避坑指南当Vue遇上FastAPI,如何优雅地打包成Windows安装程序前言最近完成了一个印章提取工具的开发,前端使用Vue 3,后端是Python FastAPI。项目开发阶段一切顺利,但到了打包交付环…...

效率系列(九) macOS 前端开发环境优化与个性化配置指南

1. 为什么需要优化macOS前端开发环境? 作为一个长期在macOS上折腾前端开发的"老司机",我深刻体会到开发环境配置对工作效率的影响。你可能遇到过这些场景:终端反应迟钝、代码补全不智能、项目切换时环境冲突...这些问题看似不大&am…...