• 037 装饰器


    引子

    >>> def func():
    ...   print("YorkFish")
    ...
    >>> func()
    YorkFish
    >>> f = func
    >>> f()
    YorkFish
    >>> id(func) - id(f)
    0
    >>> f.__name__
    'func'
    >>> 
    
    • 现在有新的需求
      • func 进行扩展:每次打印 YorkFish 之前打印当前系统时间
      • 但实现这个功能不要改动现有代码
    • 解决办法:使用装饰器

    简介

    • 在不改动函数代码的基础上无限制扩展函数功能的一种机制
    • 本质上讲,装饰器是一个 返回函数高阶函数
    • 使用:在每次要扩展的函数定义前使用 @func_name

    举例

    >>> import time  # 下面的例子就不重复这个导入操作了
    
    • 先写好函数备用
    >>> def print_date(f):
    ...   def wrapper(*args, **kwargs):
    ...     print("Date: %s" % time.strftime("%Y-%m-%d", time.localtime()))
    ...     return f(*args, **kwargs)
    ...   return wrapper
    ...
    >>> 
    

    例1

    • 对函数进行功能扩展,每次执行函数前,打印当前日期
    >>> @print_date
    ... def func():
    ...   print("YorkFish")
    ...
    >>> func()
    Date: 2019-12-20
    YorkFish
    >>> 
    
    • 装饰器的好处
      • 一处定义,多处装饰
      • 一旦被装饰,就能拥有装饰器的功能

    例2

    • 不使用 @,手动执行装饰器
    >>> def manual():
    ...   print("manual operation")
    ...
    >>> func = print_date(manual)
    >>> func()
    Date: 2019-12-20
    manual operation
    >>> 
    

    例3

    • print_date()def wrapper(*args, **kwargs) 的参数可以自定义
    >>> def cal_time(f):
    ...   def wrapper(x, y):
    ...     start = time.perf_counter_ns()
    ...     f(x, y)
    ...     stop = time.perf_counter_ns()
    ...     print(f"run time: {stop - start}")
    ...   return wrapper
    ...
    >>> @cal_time  # 装饰器要写在被装饰的函数的上方
    ... def add_two_nums(x, y):
    ...   print(f"{x} + {y} = {x + y}")
    ...
    >>> add_two_nums(10, 20)
    10 + 20 = 30
    run time: 1606600
    >>>
    

    例4

    • 两个装饰器
    >>> def deco1(f):
    ...   print("decorator1")
    ...   def wrapper():
    ...     print("decorator1's wrapper")
    ...     f()
    ...   return wrapper
    ...
    >>> def deco2(f):
    ...   print("decorator2")
    ...   def wrapper():
    ...     print("decorator2's wrapper")
    ...     f()
    ...   return wrapper
    ...
    >>> @deco2
    ... @deco1
    ... def dbl_decos():
    ...     print("double decorators")
    ...
    decorator1
    decorator2
    >>> dbl_decos()
    decorator2's wrapper
    decorator1's wrapper
    double decorators
    >>>
    

    例5

    • 沿用例4的思路,把这些代码写到一个 .py 的文件中
    def deco1(f):
        print("先穿衬衫")
        def wrapper():
            print("再脱衬衫")
            f()
        return wrapper
    
    
    def deco2(f):
        print("再穿西装")
        def wrapper():
            print("先脱西装")
            f()
        return wrapper
    
    
    @deco2
    @deco1
    def dbl_decos():
        print("over")
    
    
    if __name__ == "__main__":
        dbl_decos()
    

    >>>

    先穿衬衫
    再穿西装
    先脱西装
    再脱衬衫
    over
    
    • 装饰的过程:先执行 deco1,再执行 deco2
    • 调用的过程:先调用 deco2,再调用 deco1
  • 相关阅读:
    spring使用JdbcDaoSupport中封装的JdbcTemplate进行query
    javascript正则表达式
    Hi java新特性
    jdk 1.5
    jdk 1.6 & 1.7新特性
    core java 10~12(多线程 & I/O & Network网络编程)
    core java 8~9(GUI & AWT事件处理机制)
    core java 7 exception
    core java 5~6(OOP & 高级语言特征)
    响应式布局样例
  • 原文地址:https://www.cnblogs.com/yorkyu/p/12078084.html
Copyright © 2020-2023  润新知