【python】Python中闭包的是什么,闭包原理分析与应用实战

在这里插入图片描述

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,PyQt5,Tkinter,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏:python入门必备,基础语法到进阶实战教学
景天的主页:景天科技苑

文章目录

  • Python中闭包
    • 一、闭包的基本概念
    • 二、闭包的工作原理
    • 三、闭包的创建
      • 示例代码:
    • 四、闭包的应用场景
      • 示例代码:计数器
      • 示例代码:装饰器
    • 五、闭包的注意事项
    • 六、闭包的进阶用法
      • 1. 闭包与生成器
      • 2. 闭包与类
      • 3. 闭包与装饰器的高级用法
    • 七、总结

Python中闭包

在Python中,闭包(Closure)是一个非常重要的概念,它允许函数访问并操作其词法作用域之外的变量。闭包是由一个函数以及创建该函数时的作用域中变量的引用环境共同组成的。这个环境在闭包创建时确定,并且即便外部函数已经执行完毕,这个环境也不会被销毁。闭包在函数式编程、数据封装、装饰器等多个领域都有广泛的应用。

一、闭包的基本概念

闭包的核心在于它能够记住并访问其外部作用域中的变量,即使那个作用域已经不存在了。这是通过Python的作用域规则和函数对象实现的。

二、闭包的工作原理

闭包的工作原理依赖于Python的LEGB(Local, Enclosed, Global, Built-in)作用域规则。当Python查找一个变量的值时,它会按照以下顺序查找:

  1. Local(局部作用域):函数内部定义的变量。
  2. Enclosed(闭包作用域):闭包中外部函数定义的变量,但非全局变量。
  3. Global(全局作用域):在模块级别定义的变量。
  4. Built-in(内置作用域):Python内置的变量和函数。

闭包主要利用的是“Enclosed”作用域,这是由闭包函数和其外部函数共同创建的一个作用域。

三、闭包的创建

闭包通常是通过在一个外部函数中定义内部函数,并让内部函数引用外部函数的局部变量来创建的。然后,外部函数返回内部函数,这个返回的内部函数就形成了闭包。

示例代码:

def outer_function(text):def inner_function():print(text)return inner_function# 创建闭包
my_closure = outer_function("Hello, World!")# 调用闭包
my_closure()  # 输出: Hello, World!

在这个例子中,outer_function是外部函数,它接收一个参数text并定义了一个内部函数inner_functioninner_function没有参数,但它引用了outer_function中的变量text。当outer_function被调用时,它返回了inner_function,此时inner_function就形成了一个闭包,因为它携带了text变量的引用环境。

四、闭包的应用场景

  1. 数据封装和隐私
    闭包可以用来封装数据,通过内部函数来访问这些数据,而外部代码无法直接访问。这增加了数据的安全性。

  2. 函数工厂
    闭包可以用来创建具有特定行为或状态的函数对象。这些函数对象可以根据需要定制。

  3. 装饰器
    Python中的装饰器本质上就是闭包的一种应用。装饰器接收一个函数作为参数,并返回一个新的函数,这个新函数在某种条件下会调用原函数。

  4. 延迟计算
    闭包可以用来实现惰性求值(Lazy Evaluation),即只有在需要的时候才进行计算。

示例代码:计数器

使用闭包实现一个简单的计数器,该计数器每次调用时都会递增并返回当前的计数值。

def create_counter():count = 0  # 计数器变量def counter():nonlocal count  # 声明count为外部函数的变量count += 1return countreturn counter# 创建计数器
my_counter = create_counter()# 调用计数器
print(my_counter())  # 输出: 1
print(my_counter())  # 输出: 2
print(my_counter())  # 输出: 3

示例代码:装饰器

使用闭包实现一个简单的装饰器,该装饰器用于记录函数的执行时间。

import timedef timeit(func):def wrapper(*args, **kwargs):start_time = time.time()  # 记录开始时间result = func(*args, **kwargs)  # 调用原始函数end_time = time.time()  # 记录结束时间print(f"Function {func.__name__} took {end_time - start_time:.6f} seconds.")return resultreturn wrapper@timeit
def slow_function():time.sleep(2)  # 模拟耗时操作slow_function()  # 调用被装饰的函数,并打印执行时间

五、闭包的注意事项

  1. 内存管理:闭包会保持对其外部作用域的引用,这可能会导致一些意外的内存占用。如果闭包不再需要,并且外部作用域占用了大量内存,应该考虑如何释放这些内存。

  2. 性能影响:虽然闭包在功能上非常强大,但它们可能会引入一些性能开销。因为闭包需要维护额外的引用环境,并且这些环境可能相对较大。

  3. 可读性:闭包可以使得代码更加模块化和可重用,但有时也可能降低代码的可读性。特别是当闭包嵌套多层时,理解代码的逻辑可能会变得困难。

  4. 错误处理:在使用闭包时,需要注意错误处理。特别是当闭包访问的外部变量可能不存在或已经被修改时,应该添加适当的错误处理逻辑。

通过以上内容,你应该对Python中的闭包有了更深入的理解。闭包是Python中一个非常强大且灵活的特性,它允许函数“记住”并访问其词法作用域中的变量,即使该函数在其外部作用域之外被调用。这种特性为Python编程带来了许多便利和可能性。

六、闭包的进阶用法

除了上述基本用法外,闭包还可以与其他Python特性结合,实现更复杂和强大的功能。

1. 闭包与生成器

闭包可以与生成器结合使用,以创建可以按需生成值的函数。生成器是Python中用于创建迭代器的简单而强大的工具,而闭包则提供了一种封装状态和逻辑的方式。

def create_counter(start=0):count = startdef counter_generator():nonlocal countcount += 1yield countreturn counter_generator# 创建计数器生成器
my_counter = create_counter(5)# 使用生成器
for _ in range(3):print(next(my_counter()))  # 注意:这里有个错误,应该是 my_counter() 改为 my_counter# 正确的使用方式应该是将 my_counter 作为生成器对象,而不是每次调用都重新创建# 修正后的使用方式
counter_gen = my_counter()
for _ in range(3):print(next(counter_gen))  # 输出: 6, 7, 8

注意:上面的代码在for循环中错误地每次都调用了my_counter(),这会导致每次循环都重新创建一个新的生成器。正确的做法是将my_counter()的调用结果(即生成器对象)保存在一个变量中,并在循环中重复使用该变量。

2. 闭包与类

虽然闭包通常与函数相关联,但它们也可以与类结合使用,特别是在实现某些设计模式(如单例模式)时。然而,闭包在类中的直接使用并不常见,因为它们更常用于函数式编程中。不过,了解闭包和类之间的关系有助于深入理解Python的作用域和对象模型。

3. 闭包与装饰器的高级用法

装饰器是闭包的一个非常有用的应用。除了简单的函数包装外,装饰器还可以用于实现诸如缓存、权限检查、日志记录等复杂功能。通过闭包,装饰器可以记住额外的状态信息,并在被装饰的函数执行时使用这些信息。

def memoize(func):cache = {}def memoized_func(*args):if args in cache:return cache[args]result = func(*args)cache[args] = resultreturn resultreturn memoized_func@memoize
def fibonacci(n):if n <= 1:return nreturn fibonacci(n-1) + fibonacci(n-2)# 使用缓存的斐波那契数列函数
print(fibonacci(10))  # 第一次计算,结果将被缓存
print(fibonacci(10))  # 第二次计算,直接从缓存中获取结果

在这个例子中,memoize装饰器创建了一个缓存来存储已计算的斐波那契数列值。当fibonacci函数被调用时,它会首先检查所需的参数是否已经在缓存中。如果是,它将直接返回缓存中的结果,从而避免了重复的计算。

七、总结

闭包是Python中一个非常强大的特性,它允许函数访问并操作其外部作用域的变量。通过闭包,我们可以实现数据封装、函数工厂、装饰器等多种高级功能。然而,闭包也可能带来一些挑战,如内存管理和性能开销。因此,在使用闭包时,我们需要仔细考虑其适用性和潜在的影响。通过理解和掌握闭包的概念和用法,我们可以编写出更加灵活、模块化和可重用的Python代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/48309.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MongoDB教程(十四):MongoDB查询分析

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、查询分…

队列及其应用(用栈实现队列 力扣225)

队列概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出FIFO(First In First Out) 入队列&#xff1a;进行插入操作的一端称为队尾 出队列&#xff1a;进行删除操作的一端称为队头 队列的代码…

09.甜甜圈旋转加载动画 计数器

甜甜圈旋转加载动画 创建一个甜甜圈形状的旋转加载动画,可用于指示内容的加载。 为整个元素使用半透明的 border。排除一侧,它将作为甜甜圈的加载指示器。定义并使用合适的动画,使用 transform: rotate() 旋转元素。<body><div class="donut"></div&…

Python print() 格式化输出

Python print{} 格式化输出 1. print()2. 浮点数 (float)References 1. print() 传递给函数的值称为参数。 引号没有打印在屏幕上&#xff0c;它们只是表示字符串的起止&#xff0c;不是字符串的一部分。可以用这个函数在屏幕上打印出空行&#xff0c;只要调用 print() 就可以…

基于JAVA+SpringBoot+Vue+uniapp的微信小程序点餐平台

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 点餐小程序主要为小个…

java——类变量和类方法;代码块;内部类

一、类变量和类方法 1.1、类变量 1.1.1、类变量内存布局(静态变量放在哪里&#xff1f;) 1、JVM7及以前的近代变量放在方法区中&#xff1b;JVM8以后的静态变量放在堆中 2、不管static变量在哪里&#xff0c;共识&#xff1a; 1&#xff09;Static变量是同一个类所有对象共…

昇思25天学习打卡营第17天 | 基于MindSpore实现BERT对话情绪识别

昇思25天学习打卡营第17天 | 基于MindSpore实现BERT对话情绪识别 文章目录 昇思25天学习打卡营第17天 | 基于MindSpore实现BERT对话情绪识别BERT模型对话情绪识别BERT模型的文本情绪分类任务数据集数据下载数据加载与预处理 模型构建模型验证模型推理 总结打卡 BERT模型 BERT&…

【Espressif-ESP32S3】【VScode】安装【ESP-IDF】插件及相关工具链

一、ESP-IDF简介 二、VScode安装ESP-IDF插件 三、安装ESP-IDF、ESP-IDF-Tools以及相关工具链 四、测试例程&编译烧录 五、IDF常用指令 资料下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/15Q2rl2jpIaKfj5rATkYE6g?pwdGLNG 提取码&#xff1a;GLNG 一、ESP-…

opencv—常用函数学习_“干货“_7

目录 十九、模板匹配 从图像中提取矩形区域的子像素精度补偿 (getRectSubPix) 在图像中搜索和匹配模板 (matchTemplate) 比较两个形状&#xff08;轮廓&#xff09;的相似度 (matchShapes) 解释 二十、图像矩 计算图像或轮廓的矩 (moments) 计算图像或轮廓的Hu不变矩 (H…

IntelliJ IDEA 2024.1 最新变化 附问卷调查 AI

IntelliJ IDEA 2024.1 最新变化 问卷调查项目在线AI IntelliJ IDEA 2024.1 最新变化关键亮点全行代码补全 Ultimate对 Java 22 功能的支持新终端 Beta编辑器中的粘性行 AI AssistantAI Assistant 改进 UltimateAI Assistant 中针对 Java 和 Kotlin 的改进代码高亮显示 Ultimate…

Android14之调试广播实例(二百二十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

shell脚本检查OGG同步进程状态

服务器环境中在root用户下部署了ogg同步进程&#xff0c;在oracle用户下也部署了同步进程。在不用脚本检查的情况下&#xff0c;进程需要在root用户和oracle用户下来回切换&#xff0c;比较麻烦&#xff0c;所以考虑用脚本实现&#xff0c;在root用户下一键检查root用户和oracl…

Grid Search:解锁模型优化新境界

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

一键复制页面

<script src"./html2canvas.js"></script> <div id"target"><ol style"margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class"list-paddingleft-1"><li><p>递归遍历 DOM 树:</p&…

【Android性能优化】Android CPU占用率检测原理和优化方向

【Android性能优化】Android CPU占用率检测原理和优化方向 CPU相关知识 CPU占用的基本计算公式 (1 - 空闲态运行时间/总运行时间) * 100% Hz、Tick、Jiffies&#xff1a; Hz&#xff1a;Linux核心每隔固定周期会发出timer interrupt (IRQ 0)&#xff0c;HZ是用来定义每一秒有…

python 66 个冷知识 0720

66个有趣的Python冷知识 一行反转列表 使用切片一行反转列表&#xff1a;reversed_list my_list[::-1] 统计文件单词数量 使用 collections.Counter 统计文件中每个单词的数量&#xff1a;from collections import Counter; with open(file.txt) as f: word_count Counter(f…

【数据结构初阶】复杂度

目录 一、时间复杂度 1、时间复杂度的概念 2、大O的渐进表示法 3、常见的时间复杂度计算举例 二、空间复杂度 1、空间复杂度的概念 2、常见的空间复杂度计算举例 三、常见复杂度对比 正文开始—— 前言 一个算法&#xff0c;并非越简洁越好&#xff0c;那该如何衡量一个算法…

FLINK-checkpoint失败原因及处理方式

在 Flink 或其他分布式数据处理系统中&#xff0c;Checkpoint 失败可能由多种原因引起。以下是一些常见的原因&#xff1a; 资源不足&#xff1a; 如果 TaskManager 的内存或磁盘空间不足&#xff0c;可能无法完成状态的快照&#xff0c;导致 Checkpoint 失败。 网络问题&am…

微信小程序开发入门指南

文章目录 一、微信小程序简介二、微信小程序开发准备三、微信小程序开发框架四、微信小程序开发实例六、微信小程序开发进阶6.1 组件化开发6.2 API调用6.3 云开发 七、微信小程序开发注意事项7.1 遵守规范7.2 注意性能7.3 保护用户隐私 八、总结 大家好&#xff0c;今天将为大家…

源码安装 AMD GPGPU 生态 ROCm 备忘

0, 前言 如果初步接触 AMD这套&#xff0c;可以先在ubuntu上使用apt工具安装&#xff0c;并针对特定感兴趣的模块从源码编译安装替换&#xff0c;并开展研究。对整体感兴趣时可以考虑从源码编译安装整个ROCm生态。 1, 预制二进制通过apt 安装 待补。。。 2, 从源码安装 sudo …