Python装饰器

Posted mazinga

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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()
    

?

以上是关于Python装饰器的主要内容,如果未能解决你的问题,请参考以下文章

[TimLinux] Python 装饰器

python装饰器

python装饰器关键代码

Python装饰器

python之装饰器

python 装饰器