zoukankan      html  css  js  c++  java
  • 第八章、函数进阶之装饰器02

    第八章、函数进阶之装饰器02

    一、无参装饰器

    1. 什么是装饰器?

    装饰器指的是为被装饰对象添加功能,因此定义装饰器就是定义一个函数,只不过是该函数是用来为其他函数添加额外的功能

    注意

    • 装饰器本身是可以任意调用的对象
    • 被装饰的对象也可以是任意可调用了的对象

    2. 为什么要用装饰器

    装饰器的实现必须遵循两大原则

    • 不修改被装饰的源代码

    • 不修改被装饰的对象的调用方式

      装饰器就是在遵循以上两个原则的前提下被装饰对象添加功能

      #真正的装饰器
      import time
      def index():
          print('您好啊!')
          time.sleep(1)
      
      def deco(func):    # func = 原index
          '''装饰器'''
          def f1():    #重新创建后的index
              start = time.time()
              func()      #原index
              end = time.time()
              print(end-start)
          return f1
      
      index = deco(index)
      index()     #f1
      

    3. 怎么用装饰器

    第一种传参方式:

    def index():
        print('welcome to index')
        time.sleep(1)
    
    
    def time_count(func):
        # func = 最原始的index
        def wrapper():
            start = time.time()
            func()
            end = time.time()
            print(f"func time is {start-end}")
        return wrapper
    
    f = time_count(index)
    f()
    #index = time_count(index)  # index为被装饰函数的内存地址,即index = wrapper
    #index()  # wrapper()
    
    welcome to index
    func time is -1.0008289813995361
    

    下面方式是对第一种的再优化

    第二种传参函数:包给函数——外包(指的是再定义命名为原函数的名字的变量,被赋予了原函数的内存地址,再调用被装饰后的函数名字(),以后就可以直接用原来函数的名字调用了)

    import time
    
    
    def index():
        print('welcome to index')
        time.sleep(1)
    
    
    def time_count(func):
        # func = 最原始的index
        def wrapper():
            start = time.time()
            func()
            end = time.time()
            print(f"{func} time is {start-end}")
        return wrapper
    
    # f = time_count(index)
    # f()
    
    
    index = time_count(index)  # index为被装饰函数的内存地址,即index = wrapper
    index()  # wrapper()
    
    welcome to index
    func time is -1.0008289813995361
    

    4. 完善装饰器

    上述的装饰器,最后调用index()(实际上是被装饰后的index())的时候,其实是在调用wrapper(),因此如果原始的index()有返回值的时候,wrapper()函数的返回值应该和index()的返回值相同,也就是说,我们**需要同步原始的index()和wrapper()方法的返回值。 **具体怎么做:

    import time
    
    
    def index():
        print('welcome to index')
        time.sleep(1)
    
        return 123
    
    
    def time_count(func):
        # func = 最原始的index
        def wrapper():
            start = time.time()
            res = func()
            end = time.time()
            print(f"{func} time is {start-end}")
    
            return res
        return wrapper
    
    
    index = time_count(index)
    res = index()
    print(f"res: {res}")
    
    #此处return就已经把原始的index的返回值接收过来了
    		res = func()
            end = time.time()
            print(f"{func} time is {start-end}")
    
            return res
    

    welcome to index

    <function index at 0x102977620> time is -1.0050289630889893

    res: 123

    如果原始的home()方法需要传参,那么我们之前的装饰器是无法实现该功能的,由于有timeinner()=home(),所以给timeinner()方法传参即可。

    import time
    
    def home(name):
        print(f"welcome {name} to home page")
        time.sleep(1)
    
        return name
    
    
    def time_count(func):
        # func = 最原始的index
        def timeinner(*args, **kwargs):
            start = time.time()
            res = func(*args, **kwargs)
            end = time.time()
            print(f"{func} time is {start-end}")
    
            return res
        return timeinner
    
    
    home = time_count(home)#就相当于把time_count()的函数返回值(其实是内部函数的地址)赋值给另一个变量名(其实就是被装饰后的原函数的名字)
    
    res = home('egon')#调用了timeinner("egon")
    print(f"res: {res}")
    

    5. 装饰器语法糖

    被装饰的函数正上方单独写上@装饰器名

    import time
    
    
    def time_count(func):
        # func = 最原始的index
        def wrapper():
            start = time.time()
            func()
            end = time.time()
            print(f"{func} time is {start-end}")
        return wrapper
    
    @time_count
    def index():
        print('welcome to index')
        time.sleep(1)
    
    welcome to index
    func time is -1.000335454940796
    

    6. 装饰器模板

    #双层装饰器
    def deco(func):
        def wrapper(*args,**kwargs):
            res = func(*args,**kwargs)
            return res
        return wrapper
    
    #三层装饰器
    # 三层装饰器:给双层装饰器加参数
    def sanceng (engine):
        def outter(func):
            def wrapper(*args,**kwargs):  # wrapper是未来要运行的函数
                #加功能
                print(engine)
                res = func(*args,**kwargs)  #func是被装饰的函数
                return  res
            return wrapper
        return outter
    
    @sanceng('db')
    def shopping():
        print('shopping')
    
    shopping()
    
    

    二、有参函数

    1. 三层闭包

    # 三层装饰器:给双层装饰器加参数
    def sanceng (engine):
        def outter(func):
            def wrapper(*args,**kwargs):  # wrapper是未来要运行的函数
                #加功能
                print(engine)
                res = func(*args,**kwargs)
                print(res)#func是被装饰的函数
                return  res
            return wrapper
        return outter
    
    @sanceng('db')
    def shopping(x="666"):
        print('shopping')
        return x
    
    shopping()
    
    db
    shopping
    666
    
  • 相关阅读:
    IE盒子模型和标准W3C盒子模型
    [转载] MVC3自定义标签,给Html.ActionLink加上支持图片链接的功能
    MVC3获取登录用户名
    [转]APS.netMVC的ViewModel问题
    [转载]Js小技巧||给input type=“password”的输入框赋默认值
    [资料]aspnetdb.mdf数据库的建立和使用
    [转] .net网页中插入Flash
    [转]Membership、MembershipUser和Roles类
    [小技巧]提交按钮
    asp.net mvc中session的使用 样例
  • 原文地址:https://www.cnblogs.com/demiao/p/11341403.html
Copyright © 2011-2022 走看看