闭包学习-Python 篇

作为一个没有女朋友的码农,情人节这天只能敲敲代码,或者写写一些自己学习上的一些心得

下面我就说一说我学习“闭包” 这个结构时的一些问题和心得吧!

刚接触闭包的时候,感觉闭包很简单啊,在Python 中,不就是一个函数内再定义一个函数么,里面的函数用了外面函数的变量,这有什么难的?可随着不断的深入学习和研究,才发现了闭包结构的魅力。

首先学习闭包之前,你必须有一些Python 基础的了解,最重要的一点,就是函数名的概念,不了解的同学看下面这个例子:

def test1():
    print("in test1")

test1()          # in test1
f = test1
f()              # in test1

       分析一下,首先我们定义了一个函数 test1, 函数的作用就是打印一句话“in test1”,接着我们调用了一下这个函数,发现没有什么问题,能正常打印。

       接下来的就比较奇怪了,我们把test1 这个函数名赋值给了一个变量f (赋值这个词用的不是很恰当),然后对f 进行了函数调用,发现能打印出和调用test1 一样的内容,是不是很奇怪,我们并没有定义f 这个函数。对比以下小栗子,可能你就明白其中的原因了。

a = 10
b = a
print(b)          # 10

       第一行我们先创建了变量a,并把数值10 赋值给它,也就是数值10 的引用加一, 然后第二行是把变量a 赋值给了变量b,Python 中的赋值就是引用的传递 ,也就是将变量a 引用的内容 传递给了变量b,此时数值10 的引用再次加一,所以会有了第三行的结果,我们并没有直接把数值10 赋值给变量b,而是通过变量a 的引用传递,使得变量b 也被赋值了10.

        说了那么多,大家有没有发现什么问题?没错,函数名test1 不就相当于 变量a 吗? f 不就相当于变量b 吗?不同的是 test1 引用的是一个函数代码空间,而a 引用的是一个整数10,那么是不是就可以说函数和变量名一样,可以把它引用的代码空间传递给其他变量名? 当然是这样的,如果不成立的话,可能就不会有类似闭包这个结构了。

接下来,我们再根据下面的例子,来继续学习闭包

def outer(number_out):
    def inner(number_in):
        return number_out + number_in
    return inner

f1 = outer(100)
f2 = outer(100)
print(f1)          # <function outer.<locals>.inner at 0x000002102F5E02F0>
print(id(f1))          # 2268537422576
print(id(f2))          # 2268537422440

  分析f1 = outer(100) ,这个100 其实就是number_out 的实参,并且调用返回了 inner 这个函数名,结果为 f1 = inner,通过引用传递,将内部定义的函数 inner所引用的函数代码块,传递给了f1,此时f1 是一个 函数对象,但为什么使用相同函数调用,传入的实参也一样,两个对象却不一样?这是因为f1 = inner 的这个结果,是只有在调用outer(number_out) 的时候才去定义的inner 这个函数,作用域不同,也就不会是相同的inner 了,这也就是闭包的魅力之一了,此时调用f1(number_in) 和调用f2(numberi_in) 之间互不影响。 

如果觉得上面的例子还算简单,那么再看一下稍微复杂一点的例子:

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

line1 = line_conf(1, 2)
line2 = line_conf(3, 3)
print(line1(3))          # 5
print(line2(3))          # 12

  上面这个闭包的例子,函数line 和 变量a,b 构成闭包,通过确定line_conf 的参数a,b,转换成实际的函数就是,line1 :y = x + 2,line2:y = 3x + 3,所以我们只需要变换参数a,b 的值,就能得到不同的一次函数表达式,如果没有闭包结构,每次都要传递a, b, x 三个参数,减少了代码的可移植性,由此可以看出,闭包结构具有提高代码复用性的作用

注意:由于闭包引用了外层函数的局部变量,则外层函数的局部变量没有及时释放,消耗内存

 

总结:

      闭包结构就是一个嵌套定义的函数,在外层函数开始的时候才开始定义内层函数的定义,然后将内层函数代码块的引用传递给函数外的对象

      内层函数和使用外层函数的提供的变量所构成的整体就被称为闭包

 

扩展:闭包结构中,修改外层函数局部变量的方法

Python 2

def counter(start=0):
    count = [start]
    def inner():
        count[0] += 1
        return count[0]
    return inner


f1 = counter()
f2 = counter()

print(f1())          # 1
print(f1())          # 2
print(f2())          # 1
print(f2())          # 2

  由此也可以看出,f1 和f2 确实是互不影响的两个对象.

 

Python 3 

def counter(start=0):
    def inner():
        nonlocal start
        start += 1
        return start 
    return inner

f1 = counter()
f2 = counter()

print(f1())          # 1
print(f1())          # 2
print(f2())          # 1
print(f2())          # 2

  

 

posted @ 2019-02-14 14:34  Gnbp  阅读(216)  评论(0编辑  收藏  举报