python 闭包及个人理解

变量作用域

局部变量:在函数内部过程中定义的变量
全局变量:在函数外部模块中定义的变量
函数内部过程中,我们可以直接引用全局变量,但是对全局变量进行引用修改时,修改的是创建的一个副本,并不会修改原全局变量。
而通常,我们无法对函数内部的局部变量进行引用,因为一旦运行完毕,局部变量就会被python的回收机制清除。
闭包,就是一种保存函数内部局部变量的方式。

闭包 Closure

首先看一下维基百科的解释:
在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。
(1)这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。
(2)所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。
(3)闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
我们将这三句话标注出来,通过例子进行理解

闭包示例

以下示例中,外函数均用 out_func 表示,内函数(闭包)均用 in_func 表示
例1:

def out_func():
    msg = 'hello'
    def in_func():
        print(msg)
    return in_func
a = out_func()
a() #输出结果:hello

在外函数中,将字符串hello赋值给局部变量msg,内函数中则引用该变量并print。
a=out_func()表示:将闭包 in_func 实例化给变量a。此时使用a()时,我们并没有再调用外函数 out_func ,但是仍然引用了out_func的局部变量变量msg。
此时,根据标注【1】的维基百科解释,此时的msg称为自由变量,在out_func运行结束后,并没有被python的垃圾回收机制回收,仍可以被内函数in_func调用,并且该变量将与函数一同存在
例2:

def out_func(msg):
    def in_func():
        print(msg)
    return in_func
a = out_func('hello')
a() #输出结果:hello

在例2中,我们将字符串hello作为参数,传递给外函数out_func,并将内函数in_func实例化给a。此时,调用a()的结果为我们传递给外函数的变量hello。
此时,无论调用多少次a(),运行的结果都相当于print(‘hello’),即引用了外函数变量的内函数。这个定义,与标注【2】的解释符合:闭包是由内函数in_func与内函数引用环境(msg)组合而成的实体(实例a)
例3:

def out_func(a,b):
    def in_func(x):
        return a*x+b
    return in_func
y1 = out_func(3,2)   #y = 3 * x + 2
y2 = out_func(4,5)   #y = 4 * x + 5
print(y1(5) )#输出结果:17
print(y2(5) )#输出结果:25

在该示例中,我们进行了两次参数不同的实例化,然后向两个实例化对象中传入相同的参数5。得到的结果却不同。
a的含义相当于一元一次函数 y = 3 * x + 2
b的含义相当于一元一次函数 y = 4 * x + 5
所以,我们只需要在实例化时,传入不同的参数,即可生成不同的实例。而这一特点,正好与标注【3】的解释相符合:闭包在运行时可以有多个实例,不同的引用环境(a,b)和相同的函数 in_func 组合可以产生不同的实例(y1,y2)

闭包能干什么?

通过三个示例和维基百科的解释相互验证,我们初步了解了闭包是个什么东西。但是闭包这么复杂,到底能做什么呢?
我们以生成4个二元一次函数为例:
常规写法:

def y1(a,b):
    y = 2 * a + b
    return y
def y2(a,b):
    y = 3 * a + 2 * b
    return y
def y3(a,b):
    y = 4 * a + 3 * b
    return y
def y4(a,b):
    y = 5 * a + 4 * b
    return y
a = 2
b = 3
print(y1(a,b)) #输出结果为:7
print(y2(a,b)) #输出结果为:12
print(y3(a,b)) #输出结果为:17
print(y4(a,b)) #输出结果为:22

闭包写法:

def out_func(a,b):
    def in_func(x , y):
        return a * x + b * y
    return in_func
y1 = out_func(2,1)
y2 = out_func(3,2)
y3 = out_func(4,3)
y4 = out_func(5,4)
x = 2
y = 3
print(y1(x,y)) #输出结果:7
print(y2(x,y)) #输出结果:12
print(y3(x,y)) #输出结果:17
print(y4(x,y)) #输出结果:22

通过对照两种写法,我们可以很明显看出差距。如果用常规写法,一个函数就要定义一次。如果要生成2x+1y、3x+2y、4x+3y、5x+4y、6x+5y……等这一系列有规律的函数十个,若使用常规方法,光是定义都要写几十行,而通过闭包的写法,只需要定义一次函数,实例化十次即可搞定。
下面再举一个例子
例4:

def out_func(x6=0,x5=0,x4=0,x3=0,x2=0,x1=0,b=0):
    def in_func(x):
        y = x6*x**6+x5*x**5+x4*x**4+x3*x**3+x2*x**2+x1*x**1+b
        return y
    return in_func
a = out_func(x6=1,x1=1,b=1)
print(a(2)) #输出结果:67

此闭包通过传递参数,实例化生成的是一元六次函数。此处实例化的一元六次函数为y = x**6 + x + 1 ,若要生成一元一次,一元二次,一元三次乃至一元六次函数,通过闭包的写法,只需要向指定参数传入系数即可即可。
通过简单的示例,可以看出,闭包结构的存在,可以大大简化代码大的数量。如在需要批量创建结构类似的函数时,使用闭包写法比常规写法要方便很多。而这一特点和类有异曲同工之妙,都是面向对象的屠龙宝刀。闭包在python中还一个用途,称为装饰器。关于装饰器的用法,之后再写一篇吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值