给妹子讲python-S01E19解析Python内嵌做用域与函数闭包

欢迎关注公众号:python数据科学家python

【要点抢先看】闭包

1.python中独特的嵌套函数
2.嵌套做用域与闭包现象
3.nonlocal关键字与内嵌做用域变量修改app

前情回顾,上一节咱们介绍了变量的LEGB索引机制:对一个变量,首先在本地(函数内)查找;以后查找嵌套函数的本地做用域,而后再是查找当前的全局做用域。函数

到目前为止,咱们还有一个做用域没有介绍,就是嵌套做用域,即E,他是嵌套函数的本地做用域。spa

【妹子说】什么是嵌套函数?code

python有一个颇有意思的地方,就是def函数能够嵌套在另外一个def函数之中。调用外层函数时,运行到的内层def语句仅仅是完成对内层函数的定义,而不会去调用内层函数,除非在嵌套函数以后又显式的对其进行调用。orm

x = 99

def f1():
    x = 88
    def f2():
        print(x)
    f2()

f1()

88
复制代码

能够看出,f1中的嵌套变量x覆盖了全局变量x=99,而后f2中的本地变量按照引用规则,就引用了x=88。cdn

下面咱们来讲说嵌套做用域的一个特殊之处:对象

本地做用域在函数结束后就当即失效,而嵌套做用域在嵌套的函数返回后却仍然有效。索引

def f1():
    x = 88
    def f2():
        print(x)
    return f2

action = f1()
action()

88
复制代码

这个例子很是重要,也颇有意思,函数f1中定义了函数f2,f2引用了f1嵌套做用域内的变量x,而且f1将函数f2做为返回对象进行返回。最值得注意的是咱们经过变量action获取了返回的f2,虽然此时f1函数已经退出结束了,可是f2仍然记住了f1嵌套做用域内的变量名x。

上面这种语言现象称之为闭包:一个能记住嵌套做用域变量值的函数,尽管做用域已经不存在。

这里有一个应用就是工厂函数,工厂函数定义了一个外部的函数,这个函数简单的生成并返回一个内嵌的函数,仅仅是返回却不调用,所以经过调用这个工厂函数,能够获得内嵌函数的一个引用,内嵌函数就是经过调用工厂函数时,运行内部的def语句而建立的。

def maker(n):
    k = 8
    def action(x):
        return x ** n + k
    return action

f = maker(2)
print(f)

<function maker.<locals>.action at 0x00000000021C51E0>
复制代码

再看一个例子:

def maker(n):
    k = 8
    def action(x):
        return x ** n + k
    return action

f = maker(2)
print(f(4))

24
复制代码

这里咱们能够看出,内嵌的函数action记住了嵌套做用域内得两个嵌套变量,一个是变量k,一个是参数n,即便后面maker返回并退出。咱们经过调用外部的函数maker,获得内嵌的函数action的引用。这种函数嵌套的方法在后面要介绍的装饰器中会常常用到。这种嵌套做用域引用,就是python的函数可以保留状态信息的主要方法了。

这里接着说说另外一个关键字nonlocal

本地函数经过global声明对全局变量进行引用修改,那么对应的,内嵌函数内部想对嵌套做用域中的变量进行修改,就要使用nonlocal进行声明。

def test(num):
    in_num = num
    def nested(label):
        nonlocal in_num
        in_num += 1
        print(label, in_num)
    return nested

F = test(0)
F('a')
F('b')
F('c')

1
2
3
复制代码

这里咱们能够看到几个点,咱们在nested函数中经过nonlocal关键字引用了内嵌做用域中的变量in_num,那么咱们就能够在nested函数中修改他,即便test函数已经退出调用,这个“记忆”依然有效。

再看最后一个例子:

def test(num):
    in_num = num
    def nested(label):
        nonlocal in_num
        in_num += 1
        print(label, in_num)
    return nested

F = test(0)
F('a')
F('b')
F('c')

G = test(100)
G('mm')

1
2
3
mm 101
复制代码

屡次调用工厂函数返回的不一样内嵌函数副本F和G,彼此间的内嵌变量in_num是彼此独立隔离的。

【妹子说】这个内嵌做用域以及闭包的特性确实很是特别,确实很pythonic啊!

公众号二维码:python数据科学家:

相关文章
相关标签/搜索