19-python闭包

定义

在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。

一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。

在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例

比如我们要计算两数相加,那对于一般情况下或者说普通函数可以这样定义:

def sum(a,b):
      return a+b
print(sum(34))

那对于闭包函数呢,可以使用以下方式进行定义:

def sum(a):  
    def add(b):
        return a +b
    return add

对于闭包函数如何调用呢?

num2 = sum(2)
num3 = sum(2)
print (type(num2))
print (num3(4))

运行结果截图如下:

image

可知,num2返回的是一个方法。

Tips:

这里简单的说明一下单独是使用add 是属于函数名称或者说函数的引用,如果函数后面带括号,如add()这个属于函数的调用。

如何编写闭包函数

那如何写一个闭包函数呢?

其实也是有规律的,就是 外层函数的返回值是里层函数的函数名 。

最后载通过一个例子进行说明。

如果我们要计算一个表达式的值,比如:a*x+b=y

对于普通函数,我们一般会这样定义:


def func1(a,b,x):
....
​

那对于闭包函数呢?
我们可以先按套路写好框架,如下:

def a_line():
    def arg_y():
        return
    return arg_y
​

首先我们要考虑最外一层函数的变量,然后是里层函数的变量,接着是里层函数的返回值。

a=3,b=5
x=10,y=?

比如,我们计算的时候,在给出a,b的值后,还需要知道x的值,才可以计算出y的值

那根据这样的一个计算顺序,我们可以确定:外层函数的变量是(a,b),里层函数的变量是 x ,里层函数的返回值就是我们要计算的结果 :a*x+b=y

那函数就可以这样写了:

def a_line(a,b):
    def arg_y(x):
        return a * x + b
    return arg_y

这里 我们还可以将代码优化一下,就是将里层函数转换为lambda表达式:

def a_line(a,b):
    # def arg_y(x):
    #     return a * x + b
    return lambda x:a*x+b
    return arg_y

调用函数,得到的运行结果为:

​

line1 = a_line(3,5)
print(line1(10))
print (line1(20))
​

image

闭包作用

个人认为使用闭包的好处,就是减少了全局变量的使用,在闭包中环境变量可以持久保存相当于全局变量,在编码中应该要减少使用全局变量。其次使用闭包,可以实现轻量级的接口封装,提高代码可复用性,比如:

def line(a, b):
    def xy(x):
        return (x,a*x + b)
    return line

这个函数实现了对求一次函数的定义和求坐标的封装,我们可以通过line定义一个一次函数(line1=line(4,5)),然后通过line1(x)打印出坐标,与普通函数相比我们不需要频繁地传入a,b,x这些参数

闭包的注意事项

使用闭包是注意不要对环境变量赋值,这会被认为是局部变量比如:

def curve_pre():
    a = 10

    def curve(x):
        a = 20
        return a * x * x

    return curve
print(curve_pre()(2))
print(curve_pre().__closure__)

输入结果:

80
None

如果我想对a赋值我们要怎么做呢?我们可以使用nonlocal

def curve_pre():
    a = 10

    def curve(x):
        nonlocal a
        b = 20
        a = 20
        return a * x * x

    return curve

print(curve_pre()(2))
print(curve_pre().__closure__)
print(curve_pre().__closure__[0].cell_contents)

结果:

80
(<cell at 0x0000007E40270B28: int object at 0x00000000512D02F0>,)
10

nice生活:https://www.jianshu.com/p/84e7ed4a35c4

Jane93:https://www.jianshu.com/p/f4f78766ba1b

IT入门 感谢关注

IT入门 感谢关注 | 练习地址:www.520mg.com/it

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页