闭包函数与装饰器
闭包函数
闭:封闭;包:包裹,包含
闭包就是打破层级关系,把局部变量拿到全局使用,并且可以把外部的变量封装到函数中,然后下次就可以直接调用
闭包函数的形式
x = 10
def f1(x):
def f2():
x = 88
print(x)
return f2
f = f1(88)
f()
88
全局中相同名字的变量不会影响局部变量
闭包函数的应用
闭包的意义:返回的函数对象,不仅仅是函数对象,在该函数外还自带了作用域,这样的话该函数无论在何处调用都会优先使用自己外层包裹的作用域
应用领域:延迟计算(原先是传参数立刻执行,现在是把函数这个工具包准备好,随时可以调用),爬虫领域
装饰器
什么是装饰器
装饰器就是在不改变原有函数源代码和调用方式的同时,为函数增加额外的功能
装饰器其实也是一个函数,只不过这个函数的功能是用来为其它函数添加额外的功能
注意
装饰器本身是可以任意调用的对象
被装饰的对象也可以是任意可以调用的对象
为什么要用装饰器
日常使用的软件在上线运行的时候,软件的维护是不能修改源代码的,但可以扩展功能,这个时候装饰器的作用就非常明显了
装饰器的实现必须遵循两大原则:
- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式
装饰器的使用
如果定义了一个f函数,我们需要给该函数增加一个计时功能,修改源代码的方式如下
import time
def f():
start = time.time()
print('welcome')
time.sleep(1)
end = time.time()
print(f'run time = {end - start}')
f()
welcome
run time = 1.002185344696045
这种方法只修改一个函数的代码效率尚可,但如果有很多函数需要增加功能,可能就忙不过来了
第一种传参方式:改变调用方式(未使用装饰器)
import time
def f():
print('welcome')
time.sleep(1)
def time_count(func):
start = time.time()
func()
end = time.time()
print(f'{func}time is {end - start}')
time_count(f)
welcome
<function f at 0x000002DCDA2CC950>time is 1.0008292198181152
第二种传参方式:包给函数-外包(使用装饰器)
import time
def f():
print('welcome')
time.sleep(1)
def time_count(func):
def wrapper():
start = time.time()
func()
end = time.time()
print(f'{func}time is {end - start}')
return wrapper
f = time_count(f)
f()
welcome
<function f at 0x000002DCDA2CC7B8>time is 1.0011684894561768
这个函数是这样运行的:
f作为timr_count的参数func进入time_count函数-->
定义了wrapper函数-->
返回值是wrapper,wrapper函数开始执行-->
f作为func进入wrapper函数-->
func()就是f(),f()运行,print('welcome'),time.sleep(1)-->
print<function f at 0x000002DCDA2CC7B8>time is 1.0011684894561768
在调用的的时候,f这个实参替代了原来函数里的形参func,所以函数中的func都换成了f,在函数内部的func()也就换成了f(),而f()是一个之前定义好了的函数,所以就直接调用了
装饰器语法糖
使用装饰器有快捷方法,就是在被装饰函数正上方单独一行写上@装饰器名字
import time
def time_count(func):
def wrapper(*args,**kwargs):
start = time.time()
res = func(*args,**kwargs)
end = time.time()
print(f'{func}time is {end - start}')
return res
return wrapper
@time_count
def home(name):
print(f'hello{name}')
time.sleep(1)
return name
res = home('myz')
print(res)
hellomyz
<function home at 0x000002DCDA2CC510>time is 1.0002281665802002
myz
装饰器模板
def deco(func):
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper
有参装饰器
无参装饰器有两层函数,如果我们有另外的功能需求需要在装饰器中添加参数,那就要用到有参函数了,有参函数其实就是无参函数外面再闭包套上一层函数