python中的闭包函数
闭包函数:
在编程语⾔中,闭包(也称为词法闭包或函数闭包)是在具有⼀流函数的语⾔中实现词法范围的名称绑定的⼀种技术。操作,⼀个闭包是⼀个记录存储功能加上⼀个环境:映射关联每个⾃由变量的函数(在本地变量使⽤,但是⼀个封闭范围中定义)的价值或存储位置的名字创建绑定时关闭。与普通函数不同,闭包允许函数通过访问捕获的变量。内部函数包含对外部作⽤域⽽⾮全剧作⽤域名字的引⽤,该内部函数称为闭包。函数函数在定义阶段名字的查顺序就已经固定死了不会因为函数调⽤位置的变化⽽改变。
我们来看看要实现函数闭包要满⾜什么条件(缺⼀不可):
1.必须嵌套函数。
2.内嵌函数必须引⽤⼀个定义在闭合范围内(外部函数⾥)的变量——内部函数引⽤外部变量
3.外部函数必须返回内嵌函数——必须返回那个内部函数
闭包的作⽤:可以保持程序上⼀次运⾏后的状态然后继续执⾏。
1# 直接传参
2def index(name):
3print(name)
4
5
6# 闭包传参
7def foo():
8    num=1
9def add(n):
10        nonlocal  num
11        num += n
12return num
13return add
14 f=foo()
15print(f(1))  #2
16print(f(2))  #4
python装饰器:就是⽤于拓展原来函数功能的⼀种函数,⽬的是在不改变原函数名的情况下,给被装饰对象添加新的功能。函数装饰器有开发封闭原则;开放是对扩展开放,封闭是对修改封闭。函数装饰器必须遵守的原则:⼀是不改变被装饰对象的源代码,⼆是不改变装饰对象的调⽤⽅式。
装饰器的特殊之处在于它的返回值也是⼀个函数,这个函数是内嵌“原“”函数的函数。
⼀般⽽⾔,我们要想拓展原来函数代码,需要再给原来的函数添加新的功能,最直接的办法就是进⼊代码⾥⾯修改,但是实际⼯作中,有些时候核⼼代码并不可以直接去改,所以在不改动原代码的情况下,我们可以再定义⼀个函数,但是⽣效需要再次执⾏函数,原先的调⽤⽅式可能就会改变,可能会影响你全部的代码运⾏,⽽装饰器具有的两⼤特点就能很好的解决这个问题:
我们先定义⼀个最基础的函数:
1def sum1():
2      sum = 1 + 2
3print(sum)
4 sum1()  # 3
如果我们想查看这个函数执⾏⽤了多长时间可以加⼊import time语句查看
import time  # 查看程序运⾏⽤了多久时间
def sum1():
start = time.clock()
sum = 1+2
print(sum)
end = time.clock()
print("time used:",end - start)
sum1()  # 3    time used: 1.3777790024702245e-05
但是如果我们想想查看很多函数的运⾏时间需要⼀个函数⼀个函数的去添加,这样就会很⿇烦,我们可以考虑重新定义⼀个函数timeit(名字可以⾃⼰随便定义),将sum1的引⽤传递给他,然后在timeit中调⽤sum1并进⾏计时,这样,我们就达到了不改动sum1定义的⽬的,⽽且,不论我们看了多少个函数,我们都不⽤去修改函数定义了!
1import time  # 查看程序运⾏⽤了多少时间
2def sum1():
3    sum = 1+ 2
4print (sum)
5def timeit(func):
6    start = time.clock()
7    func()
8    end =time.clock()
9print("time used:", end - start)
10 timeit(sum1)  # 3  time used: 1.333334518519572e-05
乍⼀看,我们写的没啥问题,可以运⾏!但是还是修改了⼀部分代码,把sum1() 改成了timeit(sum1)。这样的话,如果sum1在多处都被调⽤了,你就不得不去修改这很多处的代码。所以,我们就需要杨sum1()具有和timeit(sum1)⼀样的效果,于是将timeit赋值给sum1。可是timeit 是有参数的,所以需要个⽅法去统⼀参数,将timeit(sum1)的返回值(计算运⾏时间的函数)赋值给sum1。这个时候装饰器的⽜批之处就体现出来了。
1import time  # 查看程序的运⾏时间
2def sum1():
3    sum = 1+ 2
4print (sum)
5def timeit(func):
6def test():
7        start = time.clock()
8        func()
9        end =time.clock()
10print("time used:", end - start)
11return test
12 sum1 = timeit(sum1)
13 sum1()  # 3  time used: 1.644445906174139e-05
如上就是⼀个简单的函数装饰器,我们只需要在定义sum1以后调⽤sum1之前,加上sum1= timeit(sum1),就可以达到计时的⽬的,这也就是装饰器的概念:我们在没有改变函数的调⽤⽅式的情况下就给函数增加了新的功能。但是如果我们需要装饰的函数量⽐较多,那么语法的输⼊量就会增⼤,
这⾥python就提供了语法糖:@来降低语句的输出。语法糖在书写的时候应该与被装饰对象紧紧挨着,两者之间不要有空格。
1import time
2def timeit(func):
3def test():
4          start = time.clock()
5          func()
6          end =time.clock()
7print("time used:", end - start)
8return test
9
10 @timeit  # python的语法糖 @ 后⾯加上函数的名字。
11def sum1():
12      sum = 1+ 2
13print (sum)
14 sum1()  # 3  time used: 1.5111124543221817e-05
装饰器模板:
装饰器函数的本质是闭包函数
def wrapper(func): #装饰器函数,func为被装饰函数
def inner(*args,**kwargs):
"""被装饰函数前需要添加的内容"""
ret=func(*args,**kwargs) #被装饰函数
"""被装饰函数后需要添加的内容"""
return ret
return inner
# *args :按照位置传值,多余的参数都给args,以元祖的形式存储
# **kwargs :按照关键字传值,多余的参数个kwargs,以字典的形式存储
# 使⽤⽅法
@wrapper  # 函数装饰器的语法糖
def fun():
python index函数print("hi")
装饰器升级版
1.带参数装饰器
1def out_wrapper(flag):
2def wrapper(func): #装饰器函数,func为被装饰函数
3def inner(*args,**kwargs):
4"""被装饰函数前需要添加的内容"""
5                        ret=func(*args,**kwargs) #被装饰函数
6"""被装饰函数后需要添加的内容"""
7return ret
8return inner
9return wrapper
2.多个装饰器的调⽤
1def wrapper1(func):
2def inner(*args,**ksargs):
3print('wrapper1')
4        ret=func()
5print('wrapper1')
6return ret
7return inner
8
9
10def wrapper2(func):
11def inner(*args,**ksargs):
12print('wrapper2')
13        ret=func()
14print('wrapper2')
15return ret
16return inner
17
18def wrapper3(func):
19def inner(*args,**ksargs):
20print('wrapper3')
21        ret=func()
22print('wrapper3')
23return ret
24return inner
25
26 @wrapper3
27 @wrapper2
28 @wrapper1
29def fun():
30print('func1')
31 fun()
32
33
34# 输出结果为:
35# wrapper3
36#wrapper2
37# wrapper1
38# func1
39# wrapper1
40# wrapper2
41# wrapper3
多个装饰器,运⾏顺序是从距离被装饰函数最近的⼀个装饰器开始的,即从wrapper1,wrapper2,wrapper3,⼀层⼀层嵌套,但从打印的结果可知,在被装饰函数之前运⾏的是从外到内的顺序,之后运⾏的是从内到外的顺序,类似套娃的结构。