python3装饰器

发布时间:2019-10-15 09:04:44编辑:auto阅读(2147)

    python装饰器

    预备知识

    首先我们要知道在python,一切皆对象,函数也是一个对象 

    >>> def test():
    ...     return "Hello World"

    有自己的id值,有type,有自己的值

    >>> id(test)
    140155005410568
    >>> type(test)
    <class 'function'>
    >>> test
    <function test at 0x7f78614f9d08>
    

    甚至可以赋值给其他变量

    >>> test1 = test
    >>> test1()
    'Hello World'

    哪怕是当做参数传递给别的函数,也可以当做函数的返回值

    >>> def foo(func):
    ...     print(func)
    ...     return func
    ... 
    >>> test2 = foo(test)
    <function test at 0x7f78614f9d08>
    >>> test2()
    'Hello World'

    装饰器定义

    装饰器本质其实就是一个函数, 可以让其它函数不改动源代码的情况下增加其他新功能, 比如网站经常需要的权限校验等场景


    最初的函数

    def add(x, y):
        print(x+y)
    
    add(1,2)

    现在我们有一个新需求, 计算代码执行时间

    import time
    
    def add(x, y):
        start_time = time.time
        print(x+y)
        stop_time = time.time
        print("{func} spend {time} ".format(func = "add", time = stop_time-start_time))
    
    add(1,2)

    我们当然可以这么写, 但是一来修改了源代码可能会造成一些未知的错误, 二来如果我们有一百个函数, 这样写也不现实, 这就是我们装饰器出场的时候了.

    创建一个装饰器

    import time 
    
    def timmer(func):
        """
        :param func: 被装饰的函数
        :return: 一个计算函数运行时间的函数
        """
        def wrapper(*args, **kwargs):
            """
            :param args:收集被装饰函数的参数
            :param kwargs:收集被装饰函数的关键字参数
            :return:
            """
            start_time = time.time()
            # 让进程睡一秒
            time.sleep(1)
            # 调用被装饰的函数
            result = func(*args, **kwargs)
            stop_time = time.time()
            print("{func} spend {time} ".format(func = "add", time = stop_time-start_time))
            return result
        return wrapper

    使用装饰器

    def add(x, y):
        print(x,y)
    # 因为timmer返回的是wrapper函数对象,所以执行add()相当于执行wrapper()
    add = timmer(add)
    add(1,2)

    如果觉得还是麻烦那就通过一个语法糖@符号来使用装饰器

    @timmer
    def add(x, y):
        print(x,y)
    
    add(1,2)

    这就是最基本的装饰器, 在不修改源代码的前提下为函数添加一个新功能, 调用时只需要在原函数上方添加一个 @deco_name , 在这里是@timmer


    带参数的装饰器

    python还允许我们给装饰器带上函数

    import time
    
    def timmer(flag):
        """
        :param flag: 接收装饰器的参数
        :return:
        """
        def outer_wrapper(func):
            """
            :param func: 接收被装饰的函数
            :return:
            """
            # 接收被装饰函数的参数
            def wrapper(*args, **kwargs):
                """
    
                :param args: 收集被装饰函数的参数
                :param kwargs: 收集被装饰函数的关键字参数
                :return:
                """
                if flag == "true":
                    start_time = time.time()
                    # 调用被装饰的函数
                    result = func(*args, **kwargs)
                    # 让进程睡一秒
                    time.sleep(1)
                    stop_time = time.time()
                    print("{func} spend {time} ".format(func="add", time=stop_time - start_time))
                    return result
                else:
                    print("Unexpected ending")
            return wrapper
        return outer_wrapper

    通过一个语法糖@符号来使用装饰器

    所谓的语法糖便是你不使用也可以完成任务,但是使用它可以让你的代码更简洁

    @timmer(flag="false")
    def add(x, y):
        print(x, y)
    
    add(1,2)

    被多个装饰器装饰

    当函数被多个装饰器装饰时,从里向外装饰

    @a
    @b
    @c
    def func():
        pass

    相当于

    func = a(b(c(func)))

关键字