python闭包
闭包并不只是一个python中的概念,它在函数式编程语言中应用较为广泛。
在这里,我们只浅谈python闭包。
闭包,又称闭包函数或者闭合函数,闭包中外部函数返回的不是一个具体的值,而是一个函数。一般情况下,返回的函数会赋值给一个变量,这个变量可以在后面被继续执行调用。
我们来看一个例子
def a(param1):
def b(param2):
return param1 + param2
return b
fun1 = a(1)#基数1
fun2 = a(2)#基数2
fun3 = a(3)#基数3
print(fun1(1)) #1+1
print(fun2(1)) #2+1
print(fun3(1)) #3+1
函数a的返回是函数b,而函数b的返回是a之前的param1加上b里再给的参数param2。
我们可以这样形象地认为,fun1是相加的函数,而第一个加数已经在定义fun1的时候锁死了,我们传给它的参数只能是第二个加数。
接下来,我们定义a(param1)是外函数,b(param2)是内函数,这样来解释闭包:
在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。
我们在例子中加入一些print
def a(param1):
print(a)
def b(param2):
print(b)
return param1 + param2
return b
fun1 = a(1)
fun2 = a(2)
fun3 = a(3)
print(fun1(1),fun1(1),fun2(2),fun3(3))
运行,得到
<function a at 0x000001AC399668B0>
<function a at 0x000001AC399668B0>
<function a at 0x000001AC399668B0>
<function a.<locals>.b at 0x000001AC39966940>
<function a.<locals>.b at 0x000001AC39966940>
<function a.<locals>.b at 0x000001AC399669D0>
<function a.<locals>.b at 0x000001AC39966A60>
2 2 4 6
这可以看出,在内存中,外部函数a是只存在唯一一个的,而它的内部函数b是一样的代码,不一样的对象。
浅显地说到这里,深入的话我推荐一篇博客
python装饰器
在了解了闭包这个概念之后,我相信装饰器就可以很好理解了。
这里,也从一个简单的例子说起。
def makebold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped
def makeitalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
def welcome():
return "hello world"
a=makeitalic(welcome)
b=makebold(a)
print(a())
print(b())
#结果
#<i>hello world</i>
#<b><i>hello world</i></b>
我们在两个函数里内嵌的不同的wrapped函数,负责给我们的"hello world" 左右添加起始闭合标签。这就是python 中装饰器做的事情,封装一个函数,并用自己的方法来修改它的行为。
当然,这里没有出现@符号,这是一种语法糖,我们给它加上。
什么是语法糖?
在不改变其所在位置的语法结构的前提下,实现了运行时等价。
eg:在 C 语言里用 a[i] 表示 *(a+i),用 a[i][j] 表示 *(*(a+i)+j)
def makebold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped
def makeitalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
@makebold
@makeitalic
def welcome():
return "hello world"
print(welcome())
#输出<b><i>hello world</i></b>