python装饰器

1. 装饰器

  1. 本质: 闭包函数

  2. 特点

    不修改已有函数的源代码

    不修改已有函数的调用方式

    给已有函数增加额外的功能

 

2. 理解

  1. 装饰器原则组成:

      函数 + 实参高阶函数 + 返回值高阶函数 + 嵌套函数 + 语法糖 = 装饰器

  2. 函数的本质:

    函数和变量名一致, 都是一个名字对应内存地址中的一些内容

    函数名 = 函数所在的内存地址

    函数名() = 函数内存地址所表示的内容

1 # 假设有代码
2 x = 1
3 y = x
4 def func():
5     print('hello')
6 test = z*2

 

   

  3. 装饰器

 1  improt time
 2 
 3  def timer(func) 
 4      def deco():  
 5          start = time.time()
 6          func()
 7          stop = time.time()
 8          print(stop-start)
 9      return deco
10 
11  test = timer(test) 
12 
13  def test():
14      time.sleep(2)
15      print("test is running!")   
16  test() 

    1. 首先执行第11行代码, 把test当成参数传递给timer()函数, 使得func = test

    2. 外部函数会返回deco, 传递给了test, 使得test = deco

    3. 继续执行语句, 跳过函数到了test(), 因为test地址等于deco, 所以test() = deco()

    4. 进入内部函数def deco(), 由于func = test, 所以func() = test()

    5. 执行def test(), 完毕

  3. 语法糖

    装饰器在装饰时,需要在每个函数前面加上''test = timer(test)''

    我们可以用语法糖来表示 ---- @+装饰器名称--(函数名)         @times

  4. 装饰有参数

    实际问题中, 往往函数是带有参数的, 如下函数, 我们将参数值只给予sum_num时, 就将会报错

    经过以上分析, 我们知道sum_num  = inner = fn, 于是得出sum_num() = inner() = fn(), 所以inner(), 和 fn()也必将传递一样的参数

# 添加输出日志的功能
def logging(fn):
    def inner(num1, num2):
        print("--正在努力计算--")
        fn(num1, num2)

    return inner


# 使用装饰器装饰函数
@logging
def sum_num(a, b):
    result = a + b
    print(result)


sum_num(1, 2)

  5. 通用装饰器

    我们为了将装饰器变得更加有拓展性, 可以给fn(), 和inner()函数传递不定长参数, 用于接收更大范围的数据

 1 # 添加输出日志的功能
 2 def logging(fn):
 3     def inner(*args, **kwargs):
 4         print("--正在努力计算--")
 5         result = fn(*args, **kwargs)
 6         return result
 7 
 8     return inner
 9 
10 
11 # 使用语法糖装饰函数
12 @logging
13 def sum_num(*args, **kwargs):
14     result = 0
15     for value in args:
16         result += value
17 
18     for value in kwargs.values():
19         result += value
20 
21     return result
22 
23 
24 @logging
25 def subtraction(a, b):
26     result = a - b
27     print(result)
28 
29 result = sum_num(1, 2, a=10)
30 print(result)
31 
32 subtraction(4, 2)

  6. 带有参数的装饰器

     带有参数的装饰器就是使用装饰器装饰函数的时候可以传入指定参数,语法格式: @装饰器(参数,...)

    在装饰器外面再包裹上一个函数,让最外面的函数接收参数,返回的是装饰器,因为@符号后面必须是装饰器实例。

 1 # 添加输出日志的功能
 2 def logging(flag):
 3 
 4     def decorator(fn):
 5         def inner(num1, num2):
 6             if flag == "+":
 7                 print("--正在努力加法计算--")
 8             elif flag == "-":
 9                 print("--正在努力减法计算--")
10             result = fn(num1, num2)
11             return result
12         return inner
13 
14     # 返回装饰器
15     return decorator
16 
17 
18 # 使用装饰器装饰函数
19 @logging("+")
20 def add(a, b):
21     result = a + b
22     return result
23 
24 
25 @logging("-")
26 def sub(a, b):
27     result = a - b
28     return result
29 
30 result = add(1, 2)
31 print(result)
32 
33 result = sub(1, 2)
34 print(result)