文章目录
- 前言
- 一、高阶函数
- 二、闭包(也称之为:闭包函数)
- 1、浅谈闭包函数
- 1.1、划重点
- 1.2、注意点
- 2、怎么判断是不是闭包函数呢?
- 2.1、那接下来,我们就细细的拆开解释
- 2.2、对于这个作用域,在JavaScript中的解释
- 2.3、闭包函数的相关元素查看
- 2.3.1、闭包函数的__code__属性(编译后的函数定义体)中保存着闭包函数的局部变量和自由变量的名称
- 2.3.2、自由变量的值查看
- 1、浅谈闭包函数
- 三、nonlocal关键字的使用
- 总结
前言
记录一下自己对高级函数和闭包函数的理解,以及着重点和注意点的分析和讲解。这个章节的基础是为了理解装饰器。
一、高阶函数
什么叫高阶函数呢?
定义:如果一个函数的参数,是另外一个或几个函数,那么这个函数就是高阶函数。
怎么理解呢?通俗点说:就是一个函数中要传进来的参数就是一个函数。不是具体的字段值。
举例:
注意在这里:在fun2函数里面要使用传进来的函数,那么里面必须是一个函数的完整格式,不能只是一个函数名称。
当传入多个函数作为参数时:
二、闭包(也称之为:闭包函数)
1、浅谈闭包函数
闭包这个词有点怪,其实就是一类具体一些明显特点的函数。也可以叫做:闭包函数。
对于闭包,我们先来讲闭包函数的三个特点。
(1)闭包函数内嵌套有其它函数
(2)内嵌函数引用了外层函数的变量
(3)外层函数的返回值是嵌套函数的函数名字
1.1、划重点:
第一点:闭包函数内嵌套有其它函数。也就是说:定义了一个函数fun1,那么在函数fun1中还可以定义一个函数fun2
第二点:内嵌函数引用了外层函数的变量。也就是说:在函数fun1中定义了一个变量a,现在在函数fun2中引用了fun1的变量a。
第三点:外层函数的返回值是嵌套函数的函数名字。也就是说,fun1这个外层函数的返回值,是fun2这个函数的名字。注意是名字。
1.2、注意点:
(1)如果要使用这种闭包函数,那么就要先使用一个变量去接收这个函数的返回值。
(2)这个返回值就相当于是内层函数。
我们接下来细化理解一下:
依据上面的例子:a1去接收了fun1()这个函数的返回值。那么a1就等于fun2;我们使用a1就等同于使用fun2()这个函数。
如果:当函数fun1()里面传值,但是fun2()里面不传值时,调用函数的方式有些变化:
2、怎么判断是不是闭包函数呢?
使用内层函数.__closure__方法来判断是否是闭包。如果返回的是一个cell对象,那么就是闭包函数。如果返回None就不是闭包函数。
注意:这里一定是内层函数去调用这个__closure__方法,内层函数也就是外层函数的返回值。
总结:我们可以看到闭包函数的一个特点就是,嵌套函数。另一个特点是外层函数的变量作用域在内层函数中使用。
专业术语的定义是:闭包是一种函数,一种延伸了变量作用域的函数,它会保留定义函数时变量的绑定,当定义变量的作用域不可以用了,那些绑定仍然可以被调用。
2.1、那接下来,我们就细细的拆开解释:
(1)闭包是一种函数。也就是说,闭包是个名称,全称闭包的名字也叫闭包函数。
(2)延伸了变量作用域的函数。也就是说,本来变量的作用域在函数fun1,现在把在函数fun1的变量拿到函数fun2中使用,那么这种行为就叫做延伸了变量作用域。
(3)当定义变量的作用域不可以用了,那些绑定仍然可以被调用。也就是说,当函数fun1执行完毕了(这里解释一下什么叫做执行完毕:也就是说fun1运行完,那么fun1的作用域也就跟着运行完)。那么在函数fun2中使用函数fun1的变量这种关系,是不会消除(也就是说:fun1函数运行完了,我fun2函数还是能够照样使用你fun1的作用域,对fun2函数产生不了影响)。如果消除了那就不是闭包函数了。
通过对JavaScript语言对比的新解释:那就是在一个函数里边再定义一个函数。这个内部函数一直保持有对外部函数中作用域的访问(小盒子可以一直访问大盒子但大盒子不能访问小盒子)。
对应第三点:
我们类比学习不是闭包函数的作用域:
这里的作用域list_1只能在函数fun1中被应用。
2.2、对于这个作用域,在JavaScript中的解释:
作用继承
所谓的作用域继承,就像是儿子可以继承父亲的财产一样。比如我这里有一个大的盒子作为一个父级的作用域,然后在这个大的盒子里边放一个小的盒子,作为子作用域。我们规定可以在小盒子中获取到大盒子中的东西,大盒子不能获取小盒子里的东西就称为作用域继承。
在 JS 中,道理是一样的,在一个函数里边我们再声明一个函数,内部函数可以访问外部函数作用域的变量,而外部的函数不能获取到内部函数的作用域变量。
参考博主文章:闭包:什么是闭包、闭包的作用、闭包的解决_BUG使我疯狂的博客-CSDN博客
2.3、闭包函数的相关元素查看
2.3.1、闭包函数的__code__属性(编译后的函数定义体)中保存着闭包函数的局部变量和自由变量的名称,如下:
co_varnames:查看局部变量名称
co_freevars:查看自由变量名称
顾名思义就知道这两个函数的意思了。
2.3.2、自由变量的值查看
自由变量的值是保存在__closure__[freevars].cell_contents 属性中的
三、nonlocal关键字的使用
3.1、首先我们先明白一个场景。我们在一个普通函数中把局部变量变成全局变量,使用的关键字是global。
3.2、那么在闭包函数里面可以使用global关键字的形式把局部变量改变成全局变量?
答案是:不行
(1)使用global关键字修改外层函数的变量
(2)使用nonlocal关键字修改外层函数的变量
参考文章:Python之闭包_python 装饰器_搬砖,攒路费的博客-CSDN博客
总结
闭包函数一定满足三个特征,但是满足这三个特征的函数不一定是闭包函数。因为:里面的关键字申明的变量,我们上面的例子就很好的解释这一点了。
说通俗一点:人会吃饭,但吃饭的不一定是人。