zoukankan      html  css  js  c++  java
  • python-装饰器

    定义

    在不改变原函数的调用方式的情况下,在函数前后添加功能

    一、完美的装饰器

    """
    完美的装饰器
    """
    
    import functools
    import time
    
    
    def timer(func):
        @functools.wraps(func)
        def wrap(*args, **kwargs):
            start_time = time.time()
            ret = func(*args, **kwargs)
            end_time = time.time()
            time_interval = end_time - start_time
            print('【%s】 函数 调用了 %s 秒' % (func.__name__, time_interval))
            return ret
    
        return wrap
    
    
    # 装饰器等价于:hello_world = timer(hello_world)
    @timer
    def hello_world():
        time.sleep(0.2)
        print('hello world')
        return 'ok'
    
    
    print(hello_world())
    # print(hello_world.__name__)  # @functools.wraps(func)的作用:使hello_world.__name__正确显示

    二、带参数的装饰器

    """
    需求:要求装饰器装饰函数的时候,可以传一个值,这个值表示 timer 这个装饰器是否启用:(True 启用)(False 不启用)
    使用过的场景:functools.wraps
    """
    
    import time
    from functools import wraps
    
    
    def timer(flag):
        def inner_timer(func):
            @wraps(func)
            def wrap(*args, **kwargs):
                if flag:
                    start_time = time.time()
                    ret = func(*args, **kwargs)
                    end_time = time.time()
                    print('%s 程序运行了 %s 秒' % (func.__name__, end_time - start_time))
                    return ret
                else:
                    return func(*args, **kwargs)
    
            return wrap
    
        return inner_timer
    
    
    # 装饰器等价于:hello_world = timer(True)(hello_world)
    @timer(True)
    def hello_world():
        time.sleep(0.2)
        return 'ok'
    
    
    print(hello_world())
    # print(hello_world.__name__)

    三、多个装饰器装饰一个函数

    """
    多个装饰器装饰一个函数,谁离被装饰的函数近,谁就先装饰。
    """
    
    import time
    from functools import wraps
    
    
    def wrap1(func):
        @wraps(func)
        def inner(*args, **kwargs):
            print('wrap1 装饰前')
            ret = func(*args, **kwargs)
            print('wrap1 装饰后')
            return ret
    
        return inner
    
    
    def wrap2(func):
        @wraps(func)
        def inner(*args, **kwargs):
            print('wrap2 装饰前')
            ret = func(*args, **kwargs)
            print('wrap2 装饰后')
            return ret
    
        return inner
    
    
    @wrap1
    @wrap2
    def hello_world():
        time.sleep(0.3)
        print('hello world')
    
    
    hello_world()
    """
    输出:
    wrap1 装饰前
    wrap2 装饰前
    hello world
    wrap2 装饰后
    wrap1 装饰后
    """

    补充:完美的装饰器

    经过装饰器装饰之后的函数,他们的__name__已经从原来的'now'变成了'inner'

     1 def wrapper(func):
     2     def inner(*args, **kwargs):
     3         print("在调用被装饰的函数前执行的代码")
     4         ret = func(*args, **kwargs)
     5         print("在调用被装饰的函数前执行的代码")
     6         return ret
     7     return inner
     8 
     9 
    10 @wrapper
    11 def now():
    12     print('2018-8-19')
    13 
    14 
    15 print(now.__name__)    # inner
    View Code

    因为返回的那个inner()函数名字就是'inner',所以,需要把原始函数的__name__等属性复制到inner()函数中,否则,有些依赖函数签名的代码执行就会出错。

    不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:

     1 import functools
     2 
     3 
     4 def wrapper(func):
     5     @functools.wraps(func)
     6     def inner(*args, **kwargs):
     7         print("在调用被装饰的函数前执行的代码")
     8         ret = func(*args, **kwargs)
     9         print("在调用被装饰的函数前执行的代码")
    10         return ret
    11     return inner
    12 
    13 
    14 @wrapper
    15 def now():
    16     print('2018-8-19')
    17 
    18 
    19 print(now.__name__)     # now
    View Code
  • 相关阅读:
    Python基础笔记(五)
    Python基础笔记(四)
    Python基础笔记(三)
    Python基础笔记(二)
    Python基础笔记(一)
    分页存储过程
    MD Test
    vue路由的配置技巧
    Echarts的使用与配置项
    js中call,apply,bind之间的区别
  • 原文地址:https://www.cnblogs.com/sunch/p/9503249.html
Copyright © 2011-2022 走看看