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

Python 闭包与装饰器

在 Python 学习中闭包和装饰器是两个既关联又容易混淆的知识点尤其是结合嵌套函数使用时常常分不清执行逻辑。但其实只要抓住核心原理再结合简单案例拆解就能轻松掌握。一、前置回顾函数与局部变量的生命周期要理解闭包首先要回顾函数的基本特性——尤其是局部变量的生命周期这是闭包“变量持久化”特性的基础一基础函数与局部变量函数内部定义的变量称为局部变量它的作用域仅限于函数内部生命周期从函数执行开始到函数执行结束后终止被Python垃圾回收机制销毁。deffunc():# 局部变量仅在func内部可访问local_var10print(局部变量值,local_var)func()# 执行函数输出局部变量值 10# print(local_var) # 报错NameError函数执行完毕后局部变量已销毁二无闭包时局部变量的生命周期没有闭包的情况下函数执行完毕后其内部的局部变量会立即被回收无法再被外部访问defout_func():local_var10# 外部函数的局部变量definner_func():print(内部函数访问局部变量,local_var)# 仅访问不修改inner_func()# 内部函数在外部函数内执行out_func()# 执行外部函数输出内部函数访问局部变量 10# 外部函数执行完毕后local_var被销毁无法再访问# 此时无法通过外部调用inner_func自然也无法访问local_var核心结论无闭包时局部变量随外部函数执行结束而销毁内部函数无法在外部函数执行后继续访问它。二、闭包详解嵌套函数的“隐藏魔法”在讲装饰器之前必须先吃透闭包——因为装饰器的实现本质上依赖于闭包的特性。一有闭包时局部变量的生命周期核心特性闭包的核心作用就是改变局部变量的生命周期让其在外部函数执行完毕后依然能被内部函数访问。defout_func(num1):definner_func(num2):print(num1num2)# 内部函数引用外部函数的局部变量num1returninner_func# 外部函数返回内部函数引用fout_func(10)# 外部函数执行完毕返回inner_func引用f(2)# 输出12此时num110依然存在f(1)# 输出11局部变量num1被持久化关键区别有闭包时由于内部函数引用了外部函数的局部变量Python会将该变量“打包”绑定在内部函数上即使外部函数执行完毕局部变量也不会被销毁实现“变量持久化”。二闭包的核心定义闭包不是一个语法而是一种“现象”必须同时满足以下3个条件有嵌套、有引用、有返回才能称之为闭包函数嵌套外部函数out_func内部定义了一个内部函数inner_func引用外部变量内部函数inner_func引用了外部函数out_func的局部变量num1这个变量不是全局变量也不是内部函数自身的局部变量返回内部函数外部函数的返回值是内部函数的“引用”注意是函数名不加括号不是执行结果。三nonlocal关键字闭包中修改外部函数变量默认情况下内部函数只能访问外部函数的局部变量不能修改它修改会被视为定义新的局部变量。如果需要在内部函数中修改外部函数的局部变量就需要用nonlocal关键字defout_func():count0# 外部函数的局部变量definner_func():nonlocalcount# 声明要修改外部函数的局部变量countcount1# 修改外部函数的变量print(当前计数,count)returninner_func fout_func()f()# 输出当前计数 1f()# 输出当前计数 2f()# 输出当前计数 3补充说明nonlocal仅用于嵌套函数中作用是“声明当前变量是外层函数的局部变量”只能修改外层函数的局部变量不能修改全局变量修改全局变量用global。四闭包的小误区很多新手会有两个常见误解误区1闭包是“外部函数返回内部函数的执行结果”——错返回的是内部函数的引用函数名如果加了括号return inner_func()就是执行内部函数并返回结果不是闭包误区2闭包的变量会被覆盖——如果多次调用外部函数会生成不同的闭包实例各自的变量互不影响比如f1out_func(10)f2out_func(20)f1(1)输出11f2(1)输出21误区3内部函数可以直接修改外部函数变量——错必须用nonlocal声明否则会报错或定义新的局部变量。三、装饰器详解基于闭包的“代码增强神器”理解了闭包装饰器就简单了——装饰器本质上就是一个“接收函数作为参数、返回函数的闭包”它的核心作用是在不修改原函数代码、不改变原函数调用方式的前提下给原函数增加额外功能。结合你写的所有装饰器相关代码从基础到进阶逐步拆解。一无装饰器给函数增加功能的繁琐方式在没有装饰器的情况下要给函数增加额外功能只能手动调用函数时添加代码冗余且可复用性差# 原函数评论功能defcontent():print(评论功能...)# 要给content增加“登录验证”功能只能手动添加print(登录功能...)# 额外功能content()# 原函数调用# 每次调用content都要重复写“登录功能”代码冗余无法复用二有装饰器简洁实现函数增强装饰器的出现就是为了解决上述问题通过闭包封装额外功能实现代码复用# 装饰器本质是闭包封装“登录验证”功能defout_func_login(fn):definner():print(登录功能...)# 额外功能fn()# 调用原函数returninner# 原函数defcontent():print(评论功能...)# 给原函数添加装饰功能不修改原函数代码contentout_func_login(content)content()# 调用方式不变输出登录功能... 评论功能...核心优势无需修改原函数代码无需改变调用方式可重复给多个函数添加相同功能比如给点赞、收藏函数也添加登录验证。三实用装饰器计算程序运行时间装饰器在实际开发中非常实用其中“计算函数运行时间”是高频场景importtime# 时间装饰器计算函数执行耗时deftime_decorator(fn):definner():start_timetime.time()# 记录开始时间fn()# 执行原函数end_timetime.time()# 记录结束时间print(f函数执行耗时{end_time-start_time:.4f}秒)# 计算耗时returninner# 测试函数模拟耗时操作time_decorator# 用语法糖添加装饰器deftest_func():time.sleep(1)# 模拟1秒耗时print(测试函数执行完毕)test_func()# 调用函数输出测试函数执行完毕 函数执行耗时1.00xx秒补充这个装饰器可直接复用给任何需要计算耗时的函数添加装饰无需重复编写计时代码。四进阶装饰器1可变参数的装饰器上面的装饰器只能适配无参数的原函数如果原函数有参数比如带参数的评论、登录函数就需要用可变参数装饰器deflogin_decorator(fn):# 用*args接收位置参数**kwargs接收关键字参数适配所有参数的原函数definner(*args,**kwargs):print(登录验证通过...)fn(*args,**kwargs)# 传递参数给原函数returninner# 原函数1无参数login_decoratordefcontent():print(评论功能...)# 原函数2有位置参数login_decoratordefreply(username,content):print(f{username}回复{content})# 原函数3有关键字参数login_decoratordeflike(username,post_id1001):print(f{username}点赞了帖子{post_id})# 调用测试均能正常执行content()reply(小明,写得真好)like(小红,post_id1002)核心要点*args和**kwargs可以接收任意数量、任意类型的参数让装饰器适配所有类型的原函数提升通用性。五进阶装饰器2同一个函数添加多个额外功能一个函数可以同时添加多个装饰器实现多种额外功能# 装饰器1登录验证defout_func_login(fn):definner(*args,**kwargs):print(登录功能...)fn(*args,**kwargs)returninner# 装饰器2验证功能defout_func_code(fn):definner(*args,**kwargs):print(验证功能...)fn(*args,**kwargs)returninner# 同一个函数添加两个装饰器语法糖写法out_func_login# 后装饰包在最外层先执行out_func_code# 先装饰包在内部后执行defcontent():print(评论功能...)content()# 输出顺序登录功能... → 验证功能... → 评论功能...关键规律装饰器是“层层包裹”的后写的装饰器语法糖包在最外层先执行先写的装饰器包在内部后执行。如果想调整执行顺序交换两个装饰器的位置即可。六进阶装饰器3带参数的装饰器有时候我们需要给装饰器本身传递参数比如控制装饰器的功能开关、指定参数值这就需要带参数的装饰器带参数的装饰器本质是“闭包的嵌套”外层函数接收装饰器参数中层函数接收原函数内层函数实现增强功能。# 带参数的装饰器接收参数控制是否开启日志deflog_decorator(enable_log):# 外层函数接收装饰器参数defdecorator(fn):# 中层函数接收原函数闭包核心definner(*args,**kwargs):ifenable_log:# 根据装饰器参数控制功能print(f日志执行函数{fn.__name__})fn(*args,**kwargs)returninnerreturndecorator# 语法糖写法给装饰器传递参数enable_logTrue/Falselog_decorator(enable_logTrue)# 开启日志defcontent():print(评论功能...)log_decorator(enable_logFalse)# 关闭日志defreply():print(回复功能...)content()# 输出日志执行函数content → 评论功能...reply()# 输出回复功能...无日志补充说明带参数的装饰器语法糖写法是装饰器名(参数)原始写法是content log_decorator(enable_logTrue)(content)两者效果完全一致。七远程使用装饰器核心是“装饰器的复用”——将装饰器定义在一个文件中在其他文件中导入使用提升代码的可维护性# 第一步在decorators.py文件中定义装饰器远程装饰器文件deflogin_decorator(fn):definner(*args,**kwargs):print(远程登录验证...)fn(*args,**kwargs)returninner# 第二步在其他文件中导入并使用比如main.pyfromdecoratorsimportlogin_decorator# 导入远程装饰器login_decoratordefcontent():print(评论功能...)content()# 输出远程登录验证... → 评论功能...核心价值实际开发中常用的装饰器登录、日志、计时会统一放在一个文件中供整个项目的函数复用减少重复代码。八装饰器的简化写法语法糖上面的案例中既有原始写法content 装饰器(content)也有语法糖写法装饰器两者效果完全一致但语法糖更简洁。总结一下# 原始写法defcontent():print(评论功能...)contentout_func_login(content)# 语法糖写法等价于原始写法out_func_logindefcontent():print(评论功能...)# 带参数的装饰器语法糖等价于原始写法log_decorator(enable_logTrue)defcontent():print(评论功能...)四、闭包与装饰器的关联与区别很多人会混淆闭包和装饰器其实一句话就能分清装饰器是闭包的“特殊应用”但闭包不一定是装饰器。一关联装饰器的底层实现依赖闭包所有装饰器基础装饰器、可变参数装饰器、带参数装饰器都满足“函数嵌套、引用外部变量、返回内部函数”这三个闭包的核心条件两者都利用了“变量持久化”的特性闭包持久化外部函数的变量如count、num1装饰器持久化被装饰的原函数引用如fnnonlocal关键字同样适用于装饰器闭包嵌套场景用于修改外层装饰器函数的局部变量。二区别维度闭包装饰器核心目的持久化外部变量实现数据封装如计数器增强函数功能不修改原函数如登录、计时参数要求外部函数参数可任意无强制要求如num1、enable_log中层函数必须接收一个“函数”作为参数被装饰的原函数fn应用场景数据封装、函数嵌套复用变量如计数器、局部变量持久化权限、日志、缓存、计时等函数增强场景可远程复用五、总结一常见错误总结装饰器嵌套顺序搞反记住“后装饰先执行”如果想让验证功能先执行就把out_func_code写在后面out_func_login写在前面闭包返回内部函数时加了括号return inner_func正确return inner_func()错误会直接执行内部函数并返回结果不是闭包混淆global和nonlocal修改全局变量用global修改闭包外层函数的局部变量用nonlocal不要用错装饰器未适配可变参数如果原函数有参数装饰器的inner函数必须用*args和**kwargs接收否则会报错带参数的装饰器漏写中层函数带参数的装饰器需要三层嵌套外层收装饰器参数、中层收原函数、内层实现功能少一层就会报错。二核心总结基础铺垫函数的局部变量生命周期——无闭包时随函数执行结束销毁有闭包时被持久化闭包核心嵌套函数引用外部变量返回内部函数用nonlocal可修改外层函数变量核心作用是“变量持久化”装饰器基础基于闭包实现核心作用是“不修改原函数增强功能”分为原始写法和语法糖写法装饰器进阶可变参数装饰器适配所有原函数、多装饰器嵌套实现多功能增强、带参数装饰器控制装饰器功能、远程装饰器复用装饰器核心区别装饰器是闭包的特殊应用重点在“增强函数”闭包重点在“持久化变量”。

相关文章:

Python 闭包与装饰器

在 Python 学习中,闭包和装饰器是两个既关联又容易混淆的知识点,尤其是结合嵌套函数使用时,常常分不清执行逻辑。但其实只要抓住核心原理,再结合简单案例拆解,就能轻松掌握。 一、前置回顾:函数与局部变量的…...

魔兽争霸3现代化修复指南:三步让经典游戏在Windows 10/11完美运行

魔兽争霸3现代化修复指南:三步让经典游戏在Windows 10/11完美运行 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为魔兽争霸3在现代电…...

四轴飞行器飞控编写教程

四轴飞行器飞控编写教程 写在前面 这份教程专门为零基础的初学者编写。如果你刚接触四轴飞行器不知道从何下手,听说过PID控制但不理解它是怎么工作的,看过飞控代码但感觉像天书一样看不懂,想自己动手写飞控但不知道从哪里开始——那么这份教程…...

SenseVoice-Small ONNX精彩案例分享:10分钟会议录音→带标点可编辑文本

SenseVoice-Small ONNX精彩案例分享:10分钟会议录音→带标点可编辑文本 本文展示SenseVoice-Small ONNX语音识别工具在实际会议录音转写场景中的惊艳效果,通过真实案例演示如何将10分钟会议录音快速转换为带标点、可编辑的规范文本。 1. 案例背景与工具价…...

C++ 异常安全与 RAII 模式结合

C异常安全与RAII模式结合:构建健壮资源管理体系 在C开发中,异常处理与资源管理是保证程序健壮性的核心挑战。传统的手动资源释放容易因异常抛出导致泄漏,而RAII(资源获取即初始化)模式通过对象生命周期自动化管理资源…...

Phi-4-mini-reasoning应用场景:科研助理——论文公式推导验证与符号计算辅助

Phi-4-mini-reasoning应用场景:科研助理——论文公式推导验证与符号计算辅助 1. 模型概述 Phi-4-mini-reasoning是一款由微软开发的轻量级开源模型,专注于数学推理和逻辑推导任务。这个3.8B参数的模型虽然体积小巧,但在强逻辑任务上表现出色…...

开源CLAP音频分类实战案例:上传MP3/WAV即得语义标签

开源CLAP音频分类实战案例:上传MP3/WAV即得语义标签 1. 项目概述 今天给大家介绍一个特别实用的AI工具——CLAP音频分类服务。这是一个基于LAION CLAP模型的开源项目,能够让你上传任何音频文件,就能自动识别出里面的内容是什么。 简单来说…...

OpenClaw配置备份指南:Qwen3-4B模型参数迁移方案

OpenClaw配置备份指南:Qwen3-4B模型参数迁移方案 1. 为什么需要配置备份 上周我的主力开发机突然硬盘故障,导致辛苦配置了两个月的OpenClaw环境全部丢失。最痛苦的不是重装软件,而是那些精心调试的模型参数、飞书机器人凭证和自定义技能配置…...

OpenClaw备份方案:Qwen2.5-VL-7B技能与配置的定期同步

OpenClaw备份方案:Qwen2.5-VL-7B技能与配置的定期同步 1. 为什么需要备份OpenClaw系统 上周我的开发机突然蓝屏,硬盘分区表损坏。当我重装系统后,发现过去三个月精心调教的OpenClaw配置全部丢失——包括调试好的技能参数、对接的飞书机器人…...

Electron实战:将你的网页应用打包成桌面客户端

在当今数字化时代,网页应用已经渗透到我们工作和生活的方方面面。有时我们仍然需要一个桌面客户端来提供更稳定的运行环境、离线功能或更好的系统集成。Electron作为一个强大的跨平台框架,能够帮助开发者轻松将网页应用打包成桌面客户端。无论是开发效率…...

微前端进阶:WuJie + Vite + Vue3 的无界架构性能优化全攻略

1. WuJie微前端框架的核心优势 WuJie作为新一代微前端解决方案,最大的特点就是真正实现了"无界"体验。我在多个大型项目中实测发现,它完美解决了传统iframe方案存在的样式隔离、通信困难等问题。不同于single-spa这类基于路由的微前端框架&…...

Vue3路由缓存优化指南:用keep-alive的include+max实现淘宝级页面保活

Vue3路由缓存优化实战:电商场景下的keep-alive高阶用法 电商平台的商品详情页与列表页频繁切换时,页面重载导致的性能损耗直接影响用户体验。去年双十一大促期间,某头部电商平台通过优化路由缓存策略,将页面切换速度提升了47%&…...

OpenClaw版本升级:Qwen3-4B兼容性测试与迁移方案

OpenClaw版本升级:Qwen3-4B兼容性测试与迁移方案 1. 升级前的准备工作 上周五晚上,当我准备给团队演示OpenClaw的自动化流程时,突然发现控制台弹出了版本更新提示。这个看似简单的升级通知,却让我经历了整整两天的兼容性调试。今…...

【Guava】并发编程ListenableFutureService

在技术领域,我们常常被那些闪耀的、可见的成果所吸引。今天,这个焦点无疑是大语言模型技术。它们的流畅对话、惊人的创造力,让我们得以一窥未来的轮廓。然而,作为在企业一线构建、部署和维护复杂系统的实践者,我们深知…...

OpenClaw压力测试:Qwen3-14B在并发请求下的响应延迟分析

OpenClaw压力测试:Qwen3-14B在并发请求下的响应延迟分析 1. 测试背景与目标 上周在部署OpenClaw对接本地Qwen3-14B模型时,遇到一个实际问题:当我同时触发多个自动化任务时,系统响应明显变慢,甚至偶尔会出现任务失败。…...

单例模式全解析:5种写法 + 破坏与防护

文章目录什么是单例模式?实现方式饿汉式懒汉式方式一(线程不安全)方式二(同步方法)方式三(双重检查锁 DCL)枚举什么是单例模式? 保证一个类在全局只有一个实例,并提供一个全局访问点。 适用场…...

OpenClaw压力测试:Qwen3-14B持续运行24小时稳定性报告

OpenClaw压力测试:Qwen3-14B持续运行24小时稳定性报告 1. 测试背景与目标 上周在尝试用OpenClaw自动处理一批PDF文档时,遇到了一个奇怪的现象:连续运行4小时后,系统响应速度明显下降,甚至出现了几次任务中断。这让我…...

深入理解请求限流算法的实现细节

在技术领域,我们常常被那些闪耀的、可见的成果所吸引。今天,这个焦点无疑是大语言模型技术。它们的流畅对话、惊人的创造力,让我们得以一窥未来的轮廓。然而,作为在企业一线构建、部署和维护复杂系统的实践者,我们深知…...

OpenClaw+Phi-3-vision-128k-instruct安全方案:敏感数据本地化处理指南

OpenClawPhi-3-vision-128k-instruct安全方案:敏感数据本地化处理指南 1. 为什么需要本地化处理敏感数据? 上周我帮一位做财务咨询的朋友处理季度报表时,他提到一个痛点:每次用云端AI工具分析客户财务数据都提心吊胆。这让我意识…...

Unity性能优化终极利器:MeshFusion Pro

在现代游戏开发中,性能优化始终是一个核心问题。尤其是在大型场景或高复杂度模型的项目中,Draw Call 过多、顶点数量庞大以及实时生成对象都会严重拖慢游戏帧率,影响用户体验。为了应对这些挑战,Unity 开发者社区中出现了大量优化…...

一键部署文档分析服务:YOLO X Layout模型Docker实战教程

一键部署文档分析服务:YOLO X Layout模型Docker实战教程 1. 为什么需要文档版面分析? 在日常工作中,我们经常遇到这样的场景:收到一份扫描的合同PDF,需要提取关键条款;或者拿到一份企业年报,想…...

提升代码可读性的可视化注释工具推荐

1. 代码注释的艺术化工具推荐作为一名嵌入式开发者,我深知良好的代码注释对于项目维护和团队协作的重要性。但传统的纯文本注释往往枯燥乏味,缺乏直观性。今天我要分享几款能让你的代码注释"活起来"的神器,它们不仅能提升代码可读性…...

STM32duino GNSS库深度解析:Teseo LIV3F驱动与NMEA协议实现

1. 项目概述STM32duino X-NUCLEO-GNSS1A1 是一款面向 STM32 平台的 Arduino 兼容库,专为意法半导体(STMicroelectronics)推出的 X-NUCLEO-GNSS1A1 GNSS 扩展板设计。该扩展板基于意法半导体自研的 Teseo LIV3F 单芯片 GNSS 接收器&#xff0c…...

<数据集>yolo骑行者识别<目标检测>

数据集下载链接https://blog.csdn.net/qq_53332949/article/details/159770308?spm1011.2415.3001.5331数据集格式:VOCYOLO格式 图片数量:13674张 标注数量(xml文件个数):13674 标注数量(txt文件个数):13674 标注类别数&…...

编译期类型自省如何拯救百万行遗留代码?C++27静态反射工业改造全链路拆解,从PoC到A/B灰度发布

第一章:编译期类型自省如何拯救百万行遗留代码?C27静态反射工业改造全链路拆解,从PoC到A/B灰度发布在某金融核心交易系统中,127万行C11遗留代码长期依赖宏字符串硬编码实现序列化与配置绑定,导致每次协议变更需人工同步…...

hadoop+spark+hive租房推荐系统 租房数据智能分析平台 Django框架 可视化 Requests爬虫

1、项目介绍 技术栈 Python语言、Django框架、MySQL数据库、Echarts可视化 工具、requests爬虫框架,用于58同城租房数据的采集清洗、多维度分析与可视化展示。功能模块租房数据可视化大屏租房数据管理系统首页租房数据条件查询评论功能租房数据展示项目…...

Wan2.2-I2V-A14B多场景应用:文旅宣传/电商主图/社交媒体动态生成

Wan2.2-I2V-A14B多场景应用:文旅宣传/电商主图/社交媒体动态生成 1. 开箱即用的视频创作利器 想象一下,你只需要输入一段文字描述,就能自动生成一段高清视频。这就是Wan2.2-I2V-A14B文生视频模型带来的革命性体验。无论你是文旅行业的宣传人…...

【 Claw-Code】 技术深度解析:Claude Code Agent Harness 的开源重实现

文章目录Claw-Code 技术深度解析:Claude Code Agent Harness 的开源重实现一、引言二、项目背景与定位2.1 为什么是"洁室重实现"2.2 项目核心目标三、双语言架构设计3.1 双语言实现对比3.2 Rust Workspace 模块划分四、核心组件解析4.1 运行时&#xff08…...

6 鸿蒙应用启动速度优化全流程拆解 | 鸿蒙开发筑基实战

6 鸿蒙应用启动速度优化全流程拆解 | 鸿蒙开发筑基实战 作者:杨建宾(华夏之光永存) 摘要 本文面向鸿蒙应用开发工程师,聚焦应用启动慢、首屏白屏等核心痛点,拆解从代码配置到资源处理的全流程优化方案。内容包含启动流…...

深入解析Supabase与Flutter的用户认证问题

深入解析Supabase与Flutter的用户认证问题 当我们使用Flutter开发移动应用时,用户认证是一个不可或缺的部分。而Supabase作为一个开源的数据库和后端服务,提供了强大的功能来帮助我们实现这个需求。然而,在集成过程中,我们可能会遇到一些问题。本文将详细探讨如何解决在Su…...