一、闭包

  1、外层函数嵌套内层函数,在内层函数中使用外层函数的局部变量
  2、局部变量和内层函数统称为闭包
  3、内层函数为闭包函数

  闭包函数访问外层函数的局部变量时,访问的总是该变量的最新值

 1 def outer():
 2     x = 10  # 外层函数的局部变量
 3     def inner():
 4         nonlocal x  # 关键字标记 变量x 是外层函数的局部变量
 5         x += 1
 6         return x
 7     return inner
 8 
 9 r1 = outer()  # r1 --> 函数地址(内层函数)
10 
11 print(r1())  # 11
12 print(r1())  # 12
13 print(r1())  # 13
14 
15 r = outer()
16 print(r)  # <function outer.<locals>.inner at 0x0000000003C7B9D8>
17 print(r())  #  11 此时才是调用inner()函数的调用处

二、装饰器

  闭包的应用,对于已经实现定义好了的函数功能,在不改变原函数的情况下,给其新增功能

 1 def outer(func):  # 外层函数的参数: 函数 --> 指的就是要装饰的函数
 2 
 3     def inner():
 4         print("此处代码在被装饰的函数执行之前执行")
 5         func()
 6         print("此处代码在被装饰的函数执行之后执行")
 7     return inner
 8 
 9 @outer
10 def func():
11     print("---嘻嘻哈哈---")
12 
13 func()
14 """
15     此处代码在被装饰的函数执行之前执行
16     ---嘻嘻哈哈---
17     此处代码在被装饰的函数执行之后执行
18 """
 1 import time
 2 
 3 def get_time(func):  # 装饰器--> 装饰的是函数
 4 
 5     def inner():
 6         before = time.time()  # 函数执行之前的时间戳
 7         func()
 8         after = time.time()  # 函数执行结束之后的时间戳
 9         print("函数执行时间", after - before)  # 返回值为时间戳的差值
10     return inner
11 
12 @get_time
13 def get_num():
14     for x in range(100):
15         print(x)
16 
17 get_num()
18 """
19 0
20 1
21 ...
22 98
23 99
24 函数执行时间 0.0010001659393310547
25 """

三、装饰一个带有返回值的函数

 1 def outer(func):
 2 
 3     def inner():
 4         print("调用前执行")
 5         res = func() # 此时接收原函数的返回值
 6         print("调用后执行")
 7         return res
 8     return inner
 9 
10 @outer
11 def say():
12     print("我是一个say函数")
13 
14 say()
15 """
16     调用前执行
17     我是一个say函数
18     调用后执行
19 """
20 
21 @outer
22 def say2():
23     return "我是一个say2函数"
24 
25 res = say2()
26 # 被装饰的函数say2()--> 调用的是装饰器的inner()函数 -->  res = inner()
27 print(res)
28 """
29     调用前执行
30     调用后执行
31     我是一个say2函数
32 """

四、装饰带有参数的函数

 1 def outer(func):
 2 
 3     def inner(x):  # 形参: 被装饰的函数的形参
 4         print("调用前执行")
 5         func(x)
 6         print("调用后执行")
 7     return inner
 8 
 9 @outer
10 def get_num(a):
11     print(a * 10)
12 
13 get_num(2)  # 被装饰后的函数 --> inner(2)
14 """
15     调用前执行
16     20
17     调用后执行
18 """
 1 def outer(func):
 2 
 3     def inner(*args, **kwargs):
 4         print("调用前执行")
 5         func(*args, **kwargs)
 6         print("调用后执行")
 7     return inner
 8 
 9 @outer
10 def get_num(*args, **kwargs):
11     print(args)
12     print(kwargs)
13 
14 get_num(1,2,3,4, xixi="haha", 年龄=7.5)
15 
16 """
17     调用前执行
18     (1, 2, 3, 4)
19     {'xixi': 'haha', '年龄': 7.5}
20     调用后执行
21 """

五、多个装饰器

 1 def outer1(func):
 2     def inner():
 3         print("装饰1调用前")
 4         func()
 5         print("装饰1调用后")
 6     return inner
 7 
 8 def outer2(func):
 9     def inner():
10         print("装饰2调用前")
11         func()
12         print("装饰2调用后")
13     return inner
14 
15 @outer2
16 @outer1
17 def study():
18     print("xixihaha")
19 
20 study()
21 """
22 装饰2调用前
23 装饰1调用前
24 xixihaha
25 装饰1调用后
26 装饰2调用后
27 """

六、查看被装饰函数的文档注释

  1、需要导入 from functools import wraps

  2、 装饰内层函数 @wraps(被装饰的函数)

 1 from functools import wraps
 2 
 3 def outer(func):
 4     @wraps(func)  # 解决不能查看文档注释的问题
 5     def inner():
 6         func()
 7     return inner
 8 
 9 @outer
10 def func():
11     """
12     func函数
13     :return: 无
14     """
15     print("xixi")
16 
17 print(func.__doc__)
18 """
19     func函数
20     :return: 无
21 """