从python中闭包到装饰器
一、闭包
首先要明确自由变量的含义。自由变量是指在函数中使用,但是并非在此函数中被定义的变量。
闭包不同于其他函数是因为,闭包使用了自由变量,并且闭包中的自由变量在脱离了定义该自由变量的上下文后,依然可以被正常使用。
也就是百度百科上讲的闭包是能够读取其他函数内部变量的函数,即函数+函数内部能访问到的变量的总和就是一个闭包
上代码:
def outer(a):
c = 1 # outer作用域中定义的变量c
def inner(b):
print("inner函数传进来的数字是:", b)
return a + b + c # inner函数能够读取到a和c的值
return inner
result = outer(2)
print(result) # 返回的是inner函数
print("闭包返回结果:", result(3)) # 这里的结果是 1+2+3 的值
在上述代码中inner函数与变量a和c构成一个闭包。
运行结果.png
二、装饰器
python中的装饰器就是对闭包很好的应用。装饰器顾名思义就是可以给已有函数增加其他功能,而不改动函数本身的代码,这样的做法可以让编程的过程变得更加的灵活,查阅python源码也可以看到很多装饰器的使用
装饰器本身是一个闭包,只是将外部函数的变量名变成了一个函数
装饰器的构成:
函数+实参高阶函数+返回值高阶函数+嵌套函数+语法糖
-
实参高阶函数:把一个函数名当做实参传给另一个函数
-
返回值高阶参数:返回值中包含函数名
装饰器的执行顺序是先执行装饰器里的方法,然后再执行被装饰函数的代码
上代码:
1. 被装饰的函数不带参数:
import time
def timefun(func):
def inner():
start = time.time()
func()
end = time.time()
print(func.__name__,"函数运行时间为",end-start) # 用函数对象的__name__属性,可以得到函数的名字
return inner
@timefun
def f():
time.sleep(2)
print("我现在被执行了")
f()
运行结果
这个timefun装饰器的作用非常简单,是为被装饰的函数添加程序运行时间的计时功能,此段程序的运行过程是:函数f作为参数被传入到装饰器timefun中,返回inner函数,再进行调用,现在timefun的效果已经加到函数f上面了。
以后再为其他函数添加计时功能,直接使用timefun装饰器即可,不需要重新写一遍计时的代码。
2. 被装饰的函数带返回值:
对于被装饰函数带返回值的情况,则需要在内层函数中使用变量接收,再将其返回出来
被装饰函数带返回值.png
3. 被装饰的函数有参数:
如果被装饰函数中需要参数传递,则需要在内层函数中留接收的位置
import time
def timefun(func):
def inner(a):
start = time.time()
res = func(a)
end = time.time()
print(func.__name__,"函数运行时间为",end-start) # 用函数对象的__name__属性,可以得到函数的名字
return res
return inner
@timefun
def f(a):
time.sleep(2)
print("我现在被执行了")
return "我是返回值,我返回了参数{}".format(a)
运行结果
TIPS: 如果按照解包的方式传递参数,调用的时候参数也可以不填,代码如下
import time
def timefun(func):
def inner(*args,**kwargs):
start = time.time()
res = func(args)
end = time.time()
print(func.__name__,"函数运行时间为",end-start) # 用函数对象的__name__属性,可以得到函数的名字
return res
return inner
@timefun
def f(a):
time.sleep(2)
print("我现在被执行了")
return "我是返回值,我返回了参数{}".format(a)
4. 装饰器带参数
如果要在装饰器装饰函数的时候向装饰器内部传值的话,则需要定义带参数的装饰器,定义的方式也非常简单,就是将之前的装饰器外层再嵌套一层函数,并且将第二层函数作为返回值返回,代码如下:
import time
def timefun(param):
print(param)
def outer(func):
def inner(*args,**kwargs):
start = time.time()
res = func(args)
end = time.time()
print(func.__name__,"函数运行时间为",end-start) # 用函数对象的__name__属性,可以得到函数的名字
return res
return inner
return outer
@timefun("f函数中使用的")
def f(a):
time.sleep(2)
print("我现在被执行了")
return "我是返回值,我返回了参数{}".format(a)
print(f())
print("---------------------分割线------------------------")
@timefun("g函数中使用的")
def g(a):
time.sleep(2)
print("我现在被执行了")
return "我是返回值,我返回了参数{}".format(a)
print(g())
运行结果.png