Python 闭包:函数式编程中的魔法变量容器

闭包与匿名函数的常见混淆

在编程社区中,闭包(closure)和匿名函数(anonymous function)经常被混为一谈,这种混淆有其历史根源:

  • 历史发展因素:在早期编程实践中,在函数内部定义函数并不常见,直到匿名函数广泛使用后,这种模式才流行起来
  • 概念相关性:只有当涉及嵌套函数时才会出现闭包问题,因此很多开发者是同时接触这两个概念的
  • 语法相似性:许多语言中匿名函数的语法形式恰好也是创建闭包的常见方式

关键区别:匿名函数关注的是函数的命名方式(没有标识符),而闭包关注的是函数对环境的捕获能力(访问定义体外部的非全局变量)。

闭包的核心定义

闭包是指延伸了作用域的函数,这种函数能够访问定义体中引用、但不在定义体中定义的非全局变量。判断闭包的关键要素:

  • 函数不必是匿名的
  • 必须能访问定义体之外的非全局变量
  • 即使在原始作用域消失后仍能保持这些变量的访问

深入理解闭包:移动平均值案例

面向对象实现方案

我们先看一个使用类实现的移动平均值计算器:

class Averager():def __init__(self):self.series  = []def __call__(self, new_value):self.series.append(new_value) total = sum(self.series) return total/len(self.series) # 使用方式 
avg = Averager()
print(avg(10))  # 10.0 
print(avg(11))  # 10.5 
print(avg(12))  # 11.0 

这个实现清晰明了:

  • series 存储在实例属性 self.series 中
  • 通过实现__call__ 方法使实例可调用
  • 状态保持直观可见

函数式闭包实现方案

下面是使用高阶函数和闭包的实现方式:

def make_averager():series = []def averager(new_value):series.append(new_value) total = sum(series)return total/len(series)return averager # 使用方式 
avg = make_averager()
print(avg(10))  # 10.0 
print(avg(11))  # 10.5 
print(avg(12))  # 11.0 

这个实现有几个神奇之处:

  • make_averager() 返回内部函数 averager
  • series 是 make_averager 的局部变量,理论上应在函数结束时消失
  • 但返回的 averager 函数仍然能够访问和修改 series

闭包的魔法解析

当调用 make_averager() 时:

  • 创建局部变量 series 并初始化为空列表
  • 定义嵌套函数 averager,它引用了外部变量 series
  • 返回 averager 函数时,Python 会自动捕获所需的自由变量形成闭包

关键点:闭包会保留定义函数时存在的自由变量的绑定,使得在原始作用域消失后仍能使用这些绑定。

闭包的技术实现细节

我们可以通过Python的内省工具来探查闭包的工作机制:

# 查看函数的自由变量和局部变量 
print(avg.__code__.co_varnames)  # ('new_value', 'total')
print(avg.__code__.co_freevars)  # ('series',)# 查看闭包中存储的具体值 
print(avg.__closure__)  # (<cell at 0x...: list object at 0x...>,)
print(avg.__closure__[0].cell_contents)  # [10, 11, 12]

技术要点解析:

  • code.co_freevars:保存自由变量的名称元组
  • closure:保存实际的变量绑定(cell对象列表)
  • cell_contents:访问cell对象中存储的实际值

闭包的应用价值

  • 状态保持:在不使用全局变量或类的情况下保持状态
  • 装饰器基础:Python装饰器的核心实现机制
  • 回调函数:在事件处理中保持上下文
  • 函数工厂:动态生成具有不同行为的函数
  • 延迟计算:捕获变量供后续计算使用

闭包与类的对比

特性闭包实现类实现
状态存储隐式存储在闭包中显式存储在实例属性中
代码简洁性通常更简洁需要更多样板代码
可读性对不熟悉闭包者较难理解结构清晰,易于理解
扩展性添加新功能较困难通过添加方法容易扩展
性能通常更快方法调用有额外开销

闭包的高级应用:非局部变量

在Python 3中,我们可以使用 nonlocal 关键字显式声明自由变量:

def make_counter():count = 0 def counter():nonlocal count count += 1 return count return counter 

nonlocal 声明表明变量不在当前作用域也不在全局作用域,解决了Python 2中不能修改闭包变量的限制。

闭包的注意事项

  • 内存消耗:闭包会延长捕获变量的生命周期
  • 循环引用:可能导致意外的内存泄漏
  • 可调试性:闭包中的状态不如类属性直观
  • Python 2限制:不能修改闭包中的变量(除非是可变对象)

总结

闭包是函数式编程中的强大工具,它允许函数捕获并携带其定义环境的部分状态。理解闭包的关键在于认识到函数不仅仅是代码,还包含其创建时的上下文环境。这种能力使得我们可以编写更加灵活和表达力强的代码,特别是在需要保持状态但又想避免使用全局变量或类的情况下。

闭包的概念虽然在初学阶段可能有些难以理解,但一旦掌握,它将大大扩展你解决问题的工具箱,让你能够编写出更加优雅和高效的Python代码。

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

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

相关文章

迅睿CMS导入别站数据库

<?php if (isset($_GET[go])) {$host localhost;// 数据库服务器$username uname;// 数据库用户名$password pwd;// 数据库密码$database database;// 数据库名$cmscid $_GET[cmscid];$mtabcid $_GET[mtabcid];if ($_GET[go] step1) {//第一步&#xff1a;先获取CMS…

基于C++、JsonCpp、Muduo库实现的分布式RPC通信框架

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;项目 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 项目介绍JsonCpp库简单介绍Muduo库简单介绍C11异步操作——std::future1. 使用 std::async 关联异步任务2. std::packaged_task 配…

EPSG:3857 和 EPSG:4326 的区别

EPSG:3857 和 EPSG:4326 是两种常用的空间参考系统&#xff0c;主要区别在于坐标表示方式和应用场景。以下是它们的核心差异&#xff1a; 1. 坐标系类型 EPSG:4326&#xff08;WGS84&#xff09; 地理坐标系&#xff08;Geographic Coordinate System&#xff09;&#xff0c;基…

Docker 使用与部署(超详细)

目录 引入 入门使用 部署对比 镜像仓库 命令解释 基础 常见命令 示例 数据卷的使用 数据卷的概念 数据卷的使用 挂载本地目录文件 镜像 结构 Dockerfile 容器网络 部署 DockerCompose 语法 ​编辑 基础命令 引入 当我们在 Linux 上部署一个集成了很多中间件…

JAVA在线考试系统考试管理题库管理成绩查询重复考试学生管理教师管理源码

一、源码描述 这是一套在线考试源码&#xff0c;基于SpringBootVue框架&#xff0c;后端采用JAVA语言&#xff0c;可以用于重复考试&#xff0c;一、管理员功能&#xff1a;1、考试管理&#xff1a;包括考试查询与添加考试功能&#xff0c;2、题库管理&#xff1a;管理所有题库…

在Qt Creator中使用CUDA

要在Qt Creator项目中使用CUDA进行GPU加速计算&#xff0c;你需要进行一些配置。以下是详细步骤&#xff1a; 1. 安装必要软件 安装最新版本的NVIDIA CUDA Toolkit 确保已安装Qt Creator和兼容的编译器(如MSVC或GCC) 2. 创建Qt项目 打开Qt Creator&#xff0c;创建一个新的…

qml显示视频帧(QQuickImageProvider)

一、实现方式 解码视频可以选择:opencv、ffmpeg等。 显示视频可以选择:Qt Multimedia、QQuickImageProvider、ShaderEffect、自定义QQuickItem等。 本文使用opencv解码视频,QQuickImageProvider显示视频。 二、QQuickImageProvider 中,requestImage 和 requestTexture区…

深度实时美颜:Deep-Live-Cam

深度实时美颜:Deep-Live-Cam 在这个数码化加速的时代,如何用一张图片,捕捉瞬间,将虚拟与现实无缝融合在一起?Deep-Live-Cam给出了惊人的答案。这个应用程序不仅实现了实时脸部替换和一键视频深度伪装,还通过一张图片完成了这些操作,其独特的技术让人在视频通话和直播中…

OPENGLPG第九版学习 -视口变换、裁减、剪切与反馈

文章目录 5.1 观察视图5.1.1 视图模型—相机模型OpenGL的整个处理过程中所用到的坐标系统&#xff1a;视锥体视锥体的剪切 5.1.2 视图模型--正交视图模型 5.2 用户变换5.2.1 矩阵乘法的回顾5.2.2 齐次坐标5.2.3 线性变换与矩阵SRT透视投影正交投影 5.2.4 法线变换逐像素计算法向…

卷积神经网络实战(2)

接上一篇文章&#xff0c;说到模型定义&#xff1a; class CNN(nn.Module):def __init__(self, activation"relu"):super(CNN, self).__init__()self.activation F.relu if activation "relu" else F.selu#输入通道数&#xff0c;图片是灰度图&#xff…

方案精读:业财融合转型路径和华为实践【附全文阅读】

在当今快速变化、竞争激烈的时代,业务面临不确定性,业财融合至关重要。以华为为例,其从财务到财经的转型,历经财务四统一变革、IFS 变革等,构建了包含财经能力中心(COE)、业务伙伴(BP)和财经共享中心(SSC)的财务组织架构 。通过实现财务四算拉通、提升预算预测、项目…

GAF-CNN-SSA-LSSVM故障诊断/分类预测,附带模型研究报告(Matlab)

GAF-CNN-SSA-LSSVM故障诊断/分类预测&#xff0c;附带模型研究报告&#xff08;Matlab&#xff09; 目录 GAF-CNN-SSA-LSSVM故障诊断/分类预测&#xff0c;附带模型研究报告&#xff08;Matlab&#xff09;效果一览基本描述程序设计参考资料 效果一览 基本描述 本研究提出的GA…

新型深度神经网络架构:ENet模型

语义分割技术能够为图像中的每个像素分配一个类别标签&#xff0c;这对于理解图像内容和在复杂场景中找到目标对象至关重要。在自动驾驶和增强现实等应用中&#xff0c;实时性是一个硬性要求&#xff0c;因此设计能够快速运行的卷积神经网络非常关键。 尽管深度卷积神经网络&am…

基于DGI框架的最佳实践

基于DGI框架的核心逻辑和搜索结果中的实践案例&#xff0c;以下是最精简的5步实施路径推荐&#xff1a; 1. 明确治理目标与范围&#xff08;Why & What&#xff09; 聚焦核心问题&#xff1a;优先选择1-2个业务痛点&#xff08;如数据质量低下、主数据混乱、合规风险&…

使用Prometheus监控网站是否正常打开

要使用普罗米修斯监控你的网站主页 http://gyq.com/&#xff0c;可以通过以下步骤实现。普罗米修斯本身并不直接支持 HTTP 状态码的监控&#xff0c;但可以通过 Blackbox Exporter 来完成这项任务。 方案概述 Blackbox Exporter 是一个普罗米修斯官方提供的工具&#xff0c;用…

基于YOLOv8与LSKNet的遥感图像旋转目标检测新框架 —LSKblock注意力机制在小目标检测中的性能优化与SOTA探索

针对遥感图像中目标尺度差异大、方向任意性强、背景复杂度高等挑战,本文提出一种基于 YOLOv8 与 LSKNet 的新型旋转目标检测框架。通过引入 LSKblock 注意力机制 ,实现对多尺度特征的有效建模与动态感受野调整,显著提升了模型对小目标与旋转目标的识别能力。 1. 引言 随着遥…

JVM——JVM 是如何处理异常的?

JVM 是如何处理异常的&#xff1f; 在 Java 编程语言中&#xff0c;异常处理是一种强大的机制&#xff0c;用于应对程序运行时出现的错误和意外情况。而 Java 虚拟机&#xff08;JVM&#xff09;作为 Java 程序运行的核心环境&#xff0c;在异常处理过程中扮演着至关重要的角色…

MYSQL三大日志、隔离级别(MVCC+锁机制实现)

MySQL三大日志 ​Undo Log&#xff08;回滚日志&#xff09; 作用 事务回滚时恢复数据到修改前的状态。 支持 ​​MVCC​​&#xff0c;为读操作提供历史版本数据。 存储 存放在 undo tablespace 中&#xff0c;通过回滚段管理。 格式 undo log 格式都有一个 roll_point…

访问计划(C++)

题目描述 Farmer John 计划建造 N&#xff08;1≤N≤10^5&#xff09;个农场&#xff0c;用 N−1 条道路连接&#xff0c;构成一棵树&#xff08;也就是说&#xff0c;所有农场之间都互相可以到达&#xff0c;并且没有环&#xff09;。每个农场有一头奶牛&#xff0c;品种为更…

时间同步服务

时间同步:多主机协作工作时&#xff0c;各个主机的时间同步很重要&#xff0c;时间不一致会造成很多重要应用的故障&#xff0c;如:加密协议&#xff0c;日志&#xff0c;集群等&#xff0c;利用NTP(Network Time Protocol )协议使网络中的各个计算机 时间达到同步。目前NTP协议…