zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    5.5 数据库约束
    5.4 数据库数据类型
    5.3 数据 库,表 操作
    5.2 数据库引擎
    5.1 数据库安装
    4.6 并发编程/IO模型
    4.5 协程
    4.4 线程
    在线编辑器 引入方法
    MySQL查看版本号的五种方式介绍1111111
  • 原文地址:https://www.cnblogs.com/yorkyu/p/12078084.html
Copyright © 2011-2022 走看看