1、闭包函数须满足的条件
实现一个闭包函数,须满足的条件:
- 函数中嵌套一个函数
- 外层函数返回内层函数的变量名
- 内层函数对外部作用域有一个非全局的变量进行引用
来个最简单的demo:
def funcB1():
x=100
def funcB2():
c=x*2
print(c)
return funcB2
这个时候我们直接在外面去调用funcB2看看是什么结果?
答:提示我们funcB2没有被定义,为什么呢?因为这个函数是定义在def funcB1里面,他是在函数的内部作用域里定义的,和变量x定义在函数里面一样,你在函数外面也print(x)也找不到。
2、这个时候我们提个需求: 我们需要在外面去调用函数funcB1里面的funcB2函数,该怎么处理?
答:创建对象?没用,为什么?因为他是函数里面的作用域,不是类里面的函数,如果是类里面的函数你可以创建对象 然后用对象去调用funcB2这个函数。
函数里面的变量,我如果想在外层作用域的时候去使用,那我们是怎么处理的?我们肯定是return返回出来。
# 函数里面的变量,我如果想在外层作用域的时候去使用,那我们是怎么处理的?我们肯定是return返回出来。
def funcB1():
x = 100
return x
同样的道理,我们如果想在外层作用域处理内层作用域的函数,我们可以把funcB2这个函数名返回出去,然后用变量去接收。
# 我们如果想在外层作用域处理内层作用域的函数,我们可以把funcB2返回出去
def funcB1():
x = 100
def funcB2():
c = x * 2
print(c)
return funcB2
res = funcB1()
# res的打印结果
<function funcB1.<locals>.funcB2 at 0x00000201597CAD40>
我们可以看到res的打印结果是:<function funcB1.<locals>.funcB2 at 0x00000201597CAD40>,
翻译成:返回的是funcB1函数里面定义的局部的函数funcB2
那我们可不可以通过res()去调用函数funcB1里面的函数funcB2,很明显可以
def funcB1():
x = 100
def funcB2():
c = x * 2
print(c)
return funcB2
res = funcB1()
print(res)
res()
# 打印结果
<function funcB1.<locals>.funcB2 at 0x000001A7E830AD40>
200
那如果说内部函数funcB2需要传2个参数怎么办? 直接res(11, 2)调用
def funcB1():
x = 100
def funcB2(a, b):
c = x * 2
print(c)
return funcB2
res = funcB1()
print(res)
res(11, 2)
# 打印结果
<function funcB1.<locals>.funcB2 at 0x0000028C74DFAD40>
200
3、引进闭包这个概念
上面的work()函数 外部变量可以引用,函数本身也有内部作用域
下面的funcB2函数不仅可以引用funcB1外部的变量,还可以引用x=100,这个funcB1函数内部的x变量。
区别:相比普通函数,funcB2多了一个封闭的作用域,就是funcB1里面的x=100。
注意的点:funcB2外部的函数funcB1里面的变量x=100,是改不了值的。
def funcB1():
x = 100
def funcB2(a, b):
c = x * 2
print(c)
return funcB2
res = funcB1()
res(11, 2)
# 外部改不了x的值
那我们回过头来看下闭包函数需要满足的三个条件有没有满足:
- 函数中嵌套一个函数(funcB1里面嵌套一个funcB2函数)
- 外层函数返回内层函数的变量名(funcB1返回值是 return funcB2)
- 内层函数对外部作用域有一个非全局的变量进行引用(funcB2引用外部的,而且不是全局的变量 x=100,x是funcB1函数里面作用域的变量。)
当然了不仅可以引用funcB1里面, 也可以引用函数名称里面传进来的参数。
(4)、闭包函数的实际运用(见第四篇之装饰器)