【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&…

基于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-…

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;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

【数据结构初阶】复杂度

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

源码安装 AMD GPGPU 生态 ROCm 备忘

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

C:一些题目

1.分数求和 计算1/1-1/21/3-1/41/5 …… 1/99 - 1/100 的值 #include <stdio.h>int main(){double sum 0.0; // 使用 double 类型来存储结果&#xff0c;以处理可能的小数部分int sign 1; // 符号标志&#xff0c;初始为 1 表示正数for (int i 1; i < 100; i)…

Vue3 内置组件Teleport以及Susponse

1、Teleport 1.1 概念 将组件模版中的指定的dom挂载&#xff08;传送&#xff09;到指定的dom元素上&#xff0c;如挂载到body中&#xff0c;挂载到#app选择器上面。 1.2 应用场景 经典案例如&#xff1a;模态框。 <template><teleport to"body">&l…

处理AI模型中的“Type Mismatch”报错:数据类型转换技巧

处理AI模型中的“Type Mismatch”报错&#xff1a;数据类型转换技巧 &#x1f504; 处理AI模型中的“Type Mismatch”报错&#xff1a;数据类型转换技巧 &#x1f504;摘要引言正文内容1. 错误解析&#xff1a;什么是“Type Mismatch”&#xff1f;2. 数据类型转换技巧2.1 检查…

Redis之Zset

目录 一.介绍 二.命令 三.编码方式 四.应用场景 Redis的学习专栏&#xff1a;http://t.csdnimg.cn/a8cvV 一.介绍 ZSET&#xff08;有序集合&#xff09;是 Redis 提供的一种数据结构&#xff0c;它与普通集合&#xff08;SET&#xff09;类似&#xff0c;不同之处在于每个…

【带你了解软件系统架构的演变】

🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 1. 介绍 🍋‍🟩软件系统架构的演变是一个响应技术变革、业务需求…

Tailwind CSS常见组合用法

1、一般布局组合 <main className"flex min-h-screen flex-col items-center justify-between p-24"></main>flex将元素的显示类型设置为 flexbox。这意味着子元素将以 flex 项的方式排列。min-h-screen将元素的最小高度设置为全屏高度&#xff08;视口高…

【Powershell】超越限制:获取Azure AD登录日志

你是否正在寻找一种方法来追踪 Azure Active Directory&#xff08;Azure AD&#xff09;中用户的登录活动&#xff1f; 如果是的话&#xff0c;查看Azure AD用户登录日志最简单的方法是使用Microsoft Entra管理中心。打开 https://entra.microsoft.com/&#xff0c;然后进入 监…