一文搞懂Python知识难点------装饰器

1、装饰器的本质

装饰器本质上是一个闭包函数,可以让其它函数在不需要任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数。

  • 闭包函数

    1)必须是嵌套函数,即外函数中定义了一个内函数;

    2)内函数引用了外函数作用域中(注意:非全局)的变量;

    3)外函数的返回值是内函数的引用;

    4)检测函数是否为闭包函数:function.__closure__,是闭包,返回一个cell,不是闭包,返回None

  • 函数

    1)什么是函数:组织好的、可重复使用的,用来实现单一或相关联功能的代码段;

    2)函数的优点:函数能提高应用的模块性和代码的重复利用率;

    3)函数的定义:使用def关键字;

    def func():
        print("Hello, World!") 

    4)函数的参数:根据函数在定义时和调用时,函数的参数有不同的概念;

    • 定义时:位置参数、默认参数、不定长参数;
    def func(a, b=0, *args, **kwargs): print(f"位置参数:{a}") print(f"默认参数:{b}") print(f"不定长参数:元组{args},字典{kwargs}") 
    • 调用时:必备参数(必须传)、关键字参数(可传可不传)、不定长参数(可传可不传);
    func("Hello")                            # "Hello" >> a
    func("Hello", b=1)                    # "Hello" >> a, 1 >> b func("Hello", 2) # "Hello" >> a, 2 >> b func("Hello", 2, 3, c="World") # "Hello" >> a, 2 >> b, 3 >> *args, c="World" >> **kwargs 

    5)匿名函数:使用lambda关键字,只是一个表达式,不是代码块,逻辑有限;

    add = lambda a, b: a + b
    

    6)变量作用域:LEGB;

    • L:Local,局部作用域;
    • E:Enclosing,闭包函数外的函数中;
    • G:Global,全局作用域;
    • B:Built-in,内建作用域;

    7)有关函数的几个概念;

    • 函数即变量:函数可作为参数,也可作为返回值;
    • 高阶函数:以函数作为参数或返回值的函数,内置函数map()filter()functools包中的reduce()
    • 嵌套函数:函数里定义函数;
    • 嵌套函数中变量的生命周期:正常情况下,一个函数运行结束,函数所有局部对象都会被回收,释放内存。但是闭包是一种特殊情况。闭包中,如果外函数在结束时,外函数作用域中的临时变量被内函数调用,外函数就会将该变量绑定给内函数,然后再结束;

2、装饰器应满足条件

  • 给被装饰函数添加新的功能;
  • 不能改变被装饰函数的代码;
  • 不能改变被装饰函数的调用方式;

3、装饰器的应用场景

  • 插入日志;
  • 性能测试;
  • 事务处理;
  • 缓存、权限校验;

4、装饰器的固定格式

  • 格式1

    def decorator(func):                          # decorator函数中嵌套了inner函数 def inner(*args, **kwargs): """something before func""" f = func(*args, **kwargs) # 内函数inner调用了外函数decorator作用域中的变量func """something after func""" return f return inner # 外函数decorator的返回值是inner(对内函数inner的引用) 
  • 格式2

    from functools import wraps
    
    
    def decorator(func):  @wraps def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper 

5、装饰器的演进

  • 将被装饰的函数显式传入装饰器,被装饰函数没有参数和返回值;

    import time
    
    
    def func(): print("I'm func.") def timer(f): def inner(): start = time.time() f() end = time.time() print(end - start) return inner func = timer(func) # 将函数func作为参数传递给timer装饰器,将返回结果赋值给变量func func() # func(),即执行了func 
  • 将被装饰函数放在语法糖下一行,被装饰函数不带参数,没有返回值;

    import time
    
    
    def timer(f): def inner(): start = time.time() f() end = time.time() print(end - start) return inner @timer # @timer被称为语法糖,等价于func=timer(func) def func(): print("I'm func.") func() 
  • 将被装饰函数放在语法糖下一行,被装饰函数带1个参数,没有返回值;

    import time
    
    
    def timer(f): def inner(i): start = time.time() f(i) end = time.time() print(end - start) return inner @timer def func(x): print(x) func("Hello, World!") 
  • 将被装饰函数放在语法糖下一行,被装饰函数带2个参数,没有返回值;

    import time
    
    
    def timer(f): def inner(*args, **kwargs): start = time.time() f(*args, **kwargs) end = time.time() print(end - start) return inner @timer def func(x, y): print(f"The first argument is {x}, the second is {y}.") func(2, 24) 
  • 将被装饰函数放在语法糖下一行,被装饰函数带多个参数,有返回值;

    import time
    
    
    def timer(f): def inner(*args, **kwargs): start = time.time() r = f(*args, **kwargs) end = time.time() print(end - start) return r return inner @timer def func(x, y, z=3): print(f"Arguments are {}、{} and {}.") return 'Over' func(1, 2, z=3) print(func(1, 2, z=3)) 
  • 带参数的装饰器,被装饰函数不带参数,没有返回值;

    def outer(flag):
        def decorator(f): def inner(*args, **kwargs): if flag: print("Ahead func") r = f(*args, **kwargs) if flag: print("After func") return r return inner return decorator @outer(True) def func(): print("Hello, World!") func() 
  • 多个装饰器装饰同一个函数,被装饰函数不带参数,没有返回值;

    def decorator1(f):
        def inner(): print('Decorator1, before f') f() print('Decorator1, after f') return inner def decorator2(f): def inner(): print('Decorator2, before f') f() print('Decorator2, after f') return inner @decorator2 @decorator1 def func(): print("I'm func.") 

6、装饰器的总结

Python中的装饰器一共有4种类型:函数装饰函数、函数装饰类、类装饰函数、类装饰类;

  • 函数装饰函数:函数作为参数被传入装饰器函数中;

    def decorator(f):
        def inner(*args, **kwargs): print(f"function name: {f.__name__}") r = f(*args, **kwargs) return r return inner @decorator # @decorator 等价于 addition=decorator(addition) def addition(x, y): return x + y print(addition(3, 7)) 
  • 函数装饰类:类作为参数被传入装饰器函数中;

    def decorator(cls):
        def inner(*args, **kwargs): print(f"class name: {cls.__name__}") return cls(*args, **kwargs) return inner @decorator # @decorator 等价于 Func=decorator(Func) class Func: def __init__(self, item): self.item = item def func(self): print(f"self.a = {self.a}") f = Func('Hello, World!') f.func() 
  • 类装饰函数:函数作为参数被传入装饰器类中;

    class Decorator:
        def __init__(self, f): self.f = f def __call__(self, item): print(f"function name: {self.f.__name__}") return self.f(item) @Decorator # @Decorator 等价于 func = Decorator(func).__call__ def func(i): return i print(func("Hello, World!")) 
  • 类装饰类:类作为参数被传入装饰器类中;

    class Decorator:
        def __init__(self, cls): self.cls = cls def __call__(self, item): print(f"class name: {self.cls.__name__}") return self.cls(item) @Decorator # @Decorator 等价于 Func = Decorator(Func).__call__ class Func: def __init__(self, v): self.v = v def func(self): print(self.v) f = Func("Hello, World!") f.func()

猜你喜欢

转载自www.cnblogs.com/7758520lzy/p/12697420.html