对python中闭包概念的深入理解,很容易理解哟!不学白不学 :)

Python 闭包:深入理解函数式编程的核心概念 Python闭包详解:概念、实现与应用 摘要:闭包是Python中嵌套函数对外部非全局变量的引用机制,由嵌套结构、变量引用和返回内部函数三个要素构成。它遵循LEGB作用域规则,需用nonlocal关键字修改变量。闭包广泛应用于计数器、函数柯里化、装饰器实现和回调函数等场景,能有效提高代码复用性。但需注意循环变量陷阱和内存管理问题。理解闭包有助于编写更高效的Python代码,是掌握函数式编程和高级特性的重要基础。 阅读详情

在这里插入图片描述

python是一门很常用的解释型语言,在日常使用中十分容易上手,但是实际上python中也有一些很高级很复杂的使用方式,学习这些方法对于理解整个python语言的构造、运行方式、以及提升学习者对python语言整体性的理解是很有必要的(实际上是因为我发现有的时候我写的代码不按照我想的方式来运行,可能这些和python的某些特殊设计有关,因此我觉得有必要把python学得全面一点)。

本文主要从程序的动态作用域和静态作用域入手介绍一下python函数中会出现的闭包现象的使用方式。或许在当下可能用不太上,但是我觉得这些功能还是挺牛的,总会有用的上的时候(其实是因为不熟,不知道怎么方便地用到自己的工作中)。


动态作用域和静态作用域

要解释闭包现象,我觉得首先可以理解一下静态作用域和动态作用域两个概念。

作用域,是程序设计中的概念,作用域简单解释实际上就是某个被定义的函数或者变量能够在整个脚本中被访问的范围。为什么要说是能够呢,是因为某些被定义的函数或者变量是局限性的,只有在某些特定的代码片中才能访问,比如说在函数中定义的变量只有在调用函数的时候才能被访问到。

理解了作用域后,动态作用域和静态作用域就比较好理解了。其实动态作用域和静态作用域是相对的概念,静态作用域与其名相称,也就是函数的作用域在定义的时候就已经被决定了;而对于动态作用域来说,在不同的地方对某个函数进行调用会产生不同的作用域,也即函数调用时作用域才被决定。

只说的话实际上有点抽象,看个例子就知道啦!(我暂时只会写python,就用python举例子啦,但是要知道python只支持静态作用域!!!)

抬上例子:

# 例1

# python函数,此处仅作为例子(python只支持静态作用域)

a = 'nihao'

def test1():
	print(a)
	
def test2(func):
	a = 'hello'
	func()
	
test2(test1)

上面这段代码在静态作用域和动态作用域中执行的结果是不同的。

上面这段代码在静态作用域中的执行结果是什么呢?结果是’nihao’,可能还有点懵是吧,我开始也有点懵,但是实际上这就是静态作用域的效果。怎么理解呢?实际上是因为 test1() 这个函数被定义后产生了其自身的作用域,test1()能访问到的只有全局变量和test1()内部的变量,也就是说在test2()函数中,被调用的test1()是访问不到test2()中定义的a变量的。也正是因此test2(test1)执行时test1()只能访问到全局的变量a,也就打印了"nihao"。

那么上面的例子如果在动态作用域中是怎样的呢?可能你已经猜到啦,应该是打印出"hello",这是因为在支持动态作用域的编程语言中,作用域随着我们使用函数的不同方式会发生变化。 在这个例子中,要在test2()中调用test1函数,这时test1要执行的话能够访问到的作用域是test2()中定义的所有变量和所有全局变量,当然如果test1自身有定义变量,那么也能够访问到,这么多作用域它要获取哪里的a变量呢,就是调用test1时最接近test1函数的a变量,在这个例子中也就是test2中定义的a=“hello”。访问的顺序也就是从test1向调用test1的函数的外层一层一层进行访问,直到能得到一个a变量的值就停止。(这里我也验证不了,毕竟python使用的是静态作用域:(

当前大部分的编程语言都是只采用静态作用域的,比如C/C++、C#、Python、Java等等,支持动态作用域的编程语言只有极少数如Lisp、perl(两种作用域兼具)等。

python函数闭包

了解了动态作用域和静态作用域后,要理解闭包概念就比较容易了(参见例2的简易闭包)。实际上闭包现象存在于很多编程语言中,网上能查到最多的就是关于JavaScript的闭包的解释了。JavaScript MDN学习文档中关于闭包的解释是“一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域”。其实最重要的就是最后一句,闭包能让你在一个内层函数中访问到其外层函数的作用域,因为在正常情况下一个函数的作用域是不能被访问到的,函数的作用域只在函数内部。实际上闭包的本质可以归于静态作用域和万物皆对象的理论,为什么这么说呢,先看一下例子。

抬上例子:

# 例2

def outer():   # 设置外函数
	f = 5
	def inner():   # 设置内函数
		print(f)   
	return inner    # 返回内函数给outer()

a = outer()   # 将outer()的运行结果赋值给一个变量,此时的a是一个函数即inner
a()    # 实际上是在执行inner函数,同outer()()结果

或许你还不知道return inner是什么意思。首先,万物皆对象,python中的任何东西都是对象,也正是因此,对象才能够被以变量形式存储,也即我们可以任意的将函数或者变量进行分发给不同的变量名,但是实际上这些变量名背后都是最初的那个函数或者变量。也就是说这些函数或者变量名的在内存中的储存地址不会改变。我们调用这些不同的变量名实际上是调用的最初设置的对象(函数或者变量)。

现在进一步来理解上面的代码,return inner实际上就是将一个函数即inner返回给了outer()函数。之后将outer()函数的运行结果赋值给了a,注意a代表的是outer()的运行结果。而outer()的运行结果是什么呢,是inner这个函数名,也就是a = inner,那最后一步a()实际上就代表了inner()函数的运行结果,也正是因此上述代码的运行结果是5。可以看出在整个代码的运行中,不论函数如何调用,inner函数和outer函数的作用域都是确定的,也正是因此,静态作用域在此处发挥了功能。那么静态作用域是怎么发挥功能的呢,实际上就是内函数能够获取到外函数中的变量,这些被获取到的变量可以通过内函数被获取到(这里的例子就是打印出了外函数的f变量),这样的功能在获取局部变量时应该十分好用(毕竟我没用过,只能说应该)。

开始的时候我搞混了一个地方,先上例子:

# 例3

# 和第一个例子相似,但对test1的调用方式不同。此处是把test1作为参数返回出来
a = 'nihao'

def test1():
	print(a)
	
def test2(func):
	a = 'hello'
	return func
	
test2(test1)()

此段代码运行的结果还是"nihao",也就是test1部分被调用时并没有获取到test2里面的a变量。思考之后认为上面的例2之所以打印hello,应该是因为在外函数中定义内函数时才会使内函数获取到外函数的变量,也就是说定义的外函数outer建立起了自己的作用域,直到return语句结束后才结束,inner函数由于是在外函数内部定义,因此也属于outer的作用域。但是在例3中,test1函数处于外部,是被test2所调用的,也就是说test1函数并不在test2的作用域中,也正是因此test1获取不到test2中的a变量值。

同时也能看出这里是静态作用域,因为test1和test2函数写好之后我们就能知道两个函数所具有的作用域了,要是这里是动态作用域的效果的话,test1直接访问离test1最近的a变量即test2提供的变量,那么打印的就是“hello”了(这里也侧面说明了代码中的test2(test1)()的运行对test1的调用并没有改变test1的作用域)。

现在应该大概理解了闭包的意思了吧。

除了上面获取函数变量的功能外,闭包还有一个作用就是内部函数会储存变量,也就是我们使用内函数访问到的外函数中的变量是不会从内存中清除的。正常来说函数在调用后其中的变量就不再被储存了,但是内函数所返回的变量值会继续保存在内存中直到外函数被清除。这里其实可以和之前的内容结合起来,即a = outer()其实是inner函数,再次执行a()是获取inner函数执行的结果,因此其执行并不经过外函数,从而能够储存之前获取到的变量。从整体上来看可以把内函数当做子函数,外函数为父函数,子函数能够访问父函数中的所有变量,同时子函数在父函数运行后还能够储存父函数的变量并使此变量变为全局变量。

上例子:

def outer():   # 设置外函数(父函数)
    f = 5
    w = 10
    l = [w]
    def inner():   # 设置内函数(子函数)
        nonlocal f   # 令f为非局部变量,即其改变会影响到全局
        l[0] += 1   # 使用列表等可变格式亦可设置非局部变量
        f += 1
        print("f的值",f)
        print("w的值",l[0])
    return inner    # 返回内函数给outer()
    
a = outer()   # 将outer()的运行结果赋值给一个变量,此时的a是一个函数即inner
a()
a()
del a
a()

运行结果(这里不再解释啦):

在这里插入图片描述

叮

总结一下,在python中构成闭包的两个条件:

  • 闭包含有内函数和外函数,外函数中必须返回一个函数对象(其实就是内函数)
  • 内函数中必须引用到外函数中的变量,否则若是外函数和内函数执行不相关的功能的话闭包就没意义了

参考了很多网上的资料才算大致理解,花了很多时间,感觉内容也是很丰富呀,希望以后能用上吧!哈哈。其实在python中闭包还是有用武之地的,比如装饰器的使用,下一篇文章想写一下装饰器的使用。

参考:谈谈自己的理解:python中闭包,闭包的实质
参考:https://www.zhihu.com/question/283708101
参考:https://www.zhihu.com/question/34210214
参考:静态作用域与动态作用域的区别
参考:闭包

python闭包理解 闭包就是外部函数中定义一个内部函数,内部函数引用外部函数中的变量,外部函数的返回值是内部函数 阅读详情

相关推荐

深入理解 Python 闭包(Closure)

闭包是指一个嵌套函数(内部函数),它可以访问外部函数的变量,即使外部函数已经执行完毕,这些变量仍然能被内部函数引用。

m0_62599305的博客 1563

JavaScript链式作用域

1.理解js的链式作用域的前提 1)首先要知道js的变量作用域,js的变量作用域就两种:全局和局部 2)js中当前作用域能访问其上层作用域的变量和函数 2.js链式作用域的定义: JS权威指南的描述: JavaScript中的函数运行在他们被定义的作用域里,而不是他们被执行的作用域里。 这句话很难理解,但是换做简单的描述,JS的链式作用域就是: JS中当遇到对变量名或者函数名的使用时,会首先在当前作用域查找变量或者函数,如果没有找到,就会到其上层作用域中寻找,并以此类推。 下面这个例子在很多博文中引用: v

Wnig's Blog 317

深入理解Python闭包:概念、应用与示例

它允许函数记住并访问其词法作用域(lexical scope)中的变量,即使该函数在其外部作用域被调用和执行后,这些变量仍然可以被访问。它允许函数记住并访问其词法作用域中的变量,即使在其外部函数被调用和执行后,这些变量仍然可以被访问。通过闭包,我们可以实现数据封装、私有变量、回调函数、装饰器等功能,使代码更加模块化、可重用和灵活。闭包是一个能够记住并访问其所在词法作用域(lexical scope)的变量和函数的函数对象。在Python中,闭包是由嵌套函数和它们的外部作用域中的变量组成的。

铭渊老黄 686

一文掌握JavaScript的作用域、作用域链及闭包

一文掌握JavaScript的作用域、作用域链、闭包。

saadiya10的博客 678

深入理解python的闭包函数

互相嵌套的两个函数,如果内函数使用了外函数的局部变量 并且外函数把内函数返回出来的过程,叫做闭包 里面的内函数叫做闭包函数

景天科技苑 1470

Javascript 链式作用域详细介绍

主要介绍了Javascript 链式作用域详细介绍的相关资料,需要的朋友可以参考下

作用域与作用域链

函数声明定义的函数也会被声明提升,所以函数声明定义的函数可以在函数定义代码前被调用,如下所示就是允许的。

weixin_43063398的博客 2349

Windows 10下三菱PLC控件安装报错Error Number:-119的终极解决方案(附详细步骤)

本文针对Windows 10系统安装三菱PLC控件时常见的Error Number:-119报错,提供了深度分析与终极解决方案。文章剖析了该错误源于oleaut32.dll文件版本冲突,并详细介绍了通过设置兼容性模式、手动注册DLL、直接安装MX Component以及高级系统修复等多种方法,帮助用户彻底解决此安装难题,顺利搭建PLC开发环境。

weixin_29289821的博客 329

JavaScript作用域链详解

本文通过嵌套函数示例,详解JavaScript作用域链机制:内部函数优先自身作用域,逐层查找外部函数及全局变量,解释变量访问规则及跨层级限制,帮助开发者掌握作用域链的核心原理。

m0_73941339的博客 1096

基于图神经网络的社交网络虚假账号检测系统 (Graph-based Fake Account Detection System, GFADS)

FOLLOWSRETWEETSSHAREDCOMMENTSLIKESMENTIONSUseruser_idusernamejoin_datebioavatar_urllocationverifiedis_fakeLOAD CSV这是决定模型性能的关键环节,需结合和。XXedge_indexy新账号缺乏历史数据和丰富关系。全网图可能包含数亿节点和数十亿边,难以直接训练。社交网络是动态变化的,虚假账号策略也在不断进化。获取大规模、高质量的真实/虚假账号标注数据非常困难。

Deng945201314的博客 1481

FreeRTOS CLI实战:5分钟搞定GD32串口终端移植(附LED控制源码)

本文详细介绍了如何在GD32芯片上快速移植FreeRTOS CLI(Command Line Interface)终端,实现串口交互式调试。通过DMA+空闲中断配置和LED控制命令实战,开发者可在5分钟内构建高效嵌入式调试工具,显著提升现场维护效率。

weixin_28707365的博客 450

[Python小记] 通俗的理解闭包 闭包能帮我们做什么?

热身 首先给出闭包函数的必要条件: 闭包函数必须返回一个函数对象 闭包函数返回的那个函数必须引用外部变量(一般不能是全局变量),而返回的那个函数内部不一定要return 几个典型的闭包例子: # ENV>>> Python 3.6 # NO.1 def line_conf(a, b): def line(x): r......

Rei的博客 2万+

HAL库移植实战:解决‘HAL_StatusTypeDef‘未定义报错的3个关键步骤

本文针对STM32开发中从标准库向HAL库移植时常见的'HAL_StatusTypeDef'未定义报错,提供了三个关键解决步骤:首先确保正确包含头文件入口,其次检查并配置模块使能宏,最后注意避免与标准库的同名结构体混用。文章通过实战案例解析了HAL库的模块化设计理念,帮助开发者高效解决混合编程中的编译问题。

book8的博客 207

深入理解Python闭包概念

闭包并不只是一个Python中的概念,在函数式编程语言中应用较为广泛。理解python中的闭包一方面是能够正确的使用闭包,另一方面可以好好体会和思考闭包的设计思想。 1.概念介绍 首先看一下维基上对闭包的解释: 在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自...

DrugOne 1961

基于Verilog的8位CPU设计及UART扩展实现方案,包含完整的架构设计、核心代码实现和仿真验证方法

基于Verilog的8位CPU设计及UART扩展实现方案,包含完整的架构设计、核心代码实现和仿真验证方法

a_zxswer的博客 189

PCL 直通滤波器【2026最新版】

PCL直通滤波器函数详解以及用于多字段滤波、强度滤波、获取某一时间范围内的点等高阶用法案例分享。博客长期更新,本文最近一次更新时间为:2026年3月11日。

点云侠的博客 40万+

Python闭包:深入理解与应用

闭包是Python函数式编程的核心概念,由内层函数及其引用的外部变量(自由变量)组成,能记住外层函数的环境。其三大要素为:函数嵌套、内层引用外层变量、外层返回内层函数。

an_yu_xin的博客 3827

手把手教你学simulink(40.1)--水力发电场景示例:基于 Simulink 的抽水蓄能电站水力发电

项目背景抽水蓄能电站是一种重要的储能技术,广泛应用于电力系统的调峰填谷、频率调节和备用电源。它通过在电力负荷低谷时将水从下水库抽到上水库储存,在电力负荷高峰时释放水进行发电,从而实现电能的高效利用。与传统的水电站不同,抽水蓄能电站可以在短时间内快速响应电网的需求,具有良好的灵活性和可靠性。本项目旨在使用 MATLAB/Simulink 模拟一个完整的抽水蓄能电站的水力发电过程,包括水泵-涡轮机系统、发电机、水道系统、控制系统等,并实现对电站的精确控制,确保其在不同工况下都能稳定运行。

MHD0815的博客 885

深入理解 Python 闭包:从原理到实践

简单来说,闭包是一种特殊的嵌套函数结构:在函数嵌套的前提下,内部函数引用了外部函数的变量,并且外部函数返回了这个内部函数。这种结构能让局部变量在函数执行后不被销毁,从而被全局作用域间接访问。num = 20 # 外部函数的局部变量print(num) # 内部函数引用外部变量return inner # 外部函数返回内部函数# 调用外部函数,得到内部函数的引用f() # 输出20,成功访问到outer函数的局部变量num在这个例子中,inner函数就是一个闭包,它 “记住” 了outer。

qq_73946316的博客 1646

基于深度学习的推荐系统设计与实现

基于深度学习的推荐系统设计与实现 作者:禅与计算机程序设计艺术 / Zen and the Art of Computer Programming / TextGenWebUILLM 基于深度学习的推荐系统设计与实现 关键词:深度学习, 推荐系统, 用

AI天才研究院 1078

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

深入理解 Python 中的闭包概念

闭包(Closure)是一个函数对象,它可以记住并访问定义时的作用域,即使在其外部调用时。简单来说,闭包是一个函数及其相关的环境(即自由变量)组合而成的对象。闭包的主要特性是它能够“捕获”外部作用域的变量,使得这些变量在函数外部仍然可用。

AI 音频小牛的博客 920

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

深入理解Python闭包与递归:原理、应用与实践

闭包是指在一个函数内部定义的函数,并且这个内部函数引用了外部函数的变量。即使外部函数已经执行完毕,内部函数仍然可以访问和操作这些变量递归函数(Recursive Function)是指在函数的定义中调用函数自身的函数。递归是一种强大的编程技术,特别适用于解决可以分解为相似子问题的问题。理解递归的概念和应用场景,可以帮助你编写更加简洁和优雅的代码。是一个递归函数,它接受一个或多个参数parameters。参数parameters是递归函数的输入,通常用于表示当前问题的状态或规模。

2401_88862650的博客 2021

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Python编程精进:深入理解核心概念

然而,由于GIL(全局解释器锁,看下一点),一次只能有一个线程执行Python字节码,这限制了真正的并行性。的引入,Python现在对异步编程有了强大的支持。尽管Python不像Java那样是一个严格的基于类的编程语言,但你确实需要了解良好的OOP概念和最佳实践,才能在现实世界项目中做出贡献。但是,你在编程旅程中越是高级,你就越想要控制权,这就是为什么学习Python中的内存管理概念是必要的。有不同的方式可以做到这一点,不同的并发风味有细微的差别,只有当你深入了解它们的内部工作时才会变得清晰。

zmh_fuhuasishui的专栏 952

Python:深入理解闭包

函数对象的作用域 函数对象是使用def语句定义的,函数对象的作用域与def所在的层级相同。比如下面代码,我们在line_conf函数的隶属范围内定义的函数line,就只能在line_conf的隶属范围内调用。 代码: def line_conf(): def line(x): return 2 * x + 1 print(line(5)) #with...

来自江南的你的博客 739

【深入理解Python中的闭包】如何有效使用嵌套函数和状态捕获!

在 Python 中,闭包是一个能够捕获其所在环境中的变量的函数。也就是说,闭包可以访问函数外部的局部变量,并且在闭包创建时,外部的局部变量会与闭包绑定,进而在闭包被调用时能够访问这些变量,即便外部函数已经执行完毕。闭包可以让程序的行为更加灵活,因为它允许我们在函数内存储状态,而不需要使用全局变量或者复杂的类结构。闭包作为 Python 中强大的工具,允许我们捕获和持久化函数外部的变量,从而灵活地处理状态和逻辑。它在许多场景中非常有用,如回调、装饰器、事件处理等。

萧鼎的博客 1166

深入理解python中闭包,闭包的实质

闭包这个概念好难理解,身边朋友们好多都稀里糊涂的,稀里糊涂的林老冷希望写下这篇文章能够对稀里糊涂的伙伴们有一些帮助~   请大家跟我理解一下,如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,内部的我们叫他内函数。 闭包:    在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。 一般情况

pushiqiang的博客 3906
上一篇: 爬虫中常见的post和get有什么区别
下一篇: python中装饰器的使用方式,非常简单易上手哦
你大佬来啦
博客等级 码龄7年 322粉丝 62原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值