• python-


    目录

    • 装饰器的形成过程
    • 装饰器的使用方式
      • 装饰器 - - 带参数的装饰器
      • 装饰器 - - 带有不定参数的装饰器
      • 装饰器 - - 带返回值的装饰器
      • 装饰器 - - 三层嵌套函数
      • 装饰器 - - 多个装饰器装饰同一个函数
      • 查看函数信息的一些方法
      • 完美的装饰器
    • 装饰器主要功能和装饰器固定结构
    • 开放封闭原则
    • 相关练习题

    1,装饰器的形成过程

    1.1 统计函数执行的时间

    1.1.1 初步实现

    import time
    def timer(func):
        start = time.time()
        func()
        end = time.time()
        print(end - start)
    
    def func1():
        print("in func1")
        time.sleep(0.1)
    timer(func1)
    
    # 结果呈现
    in func1
    0.10027360916137695
    

    1.1.2 实现调用func1,但是能实现调用timer方法的效果

    import time
    def timer(func):
        def inner():
            start = time.time()
            func()
            end = time.time()
            print(end - start)
        return inner
    
    def func1():
        print("in func1")
        time.sleep(0.2)
    func1 = timer(func1)
    func1()
    
    # 结果呈现
    in func1
    0.20004010200500488
    

    现在已经基本上完美了,唯一碍眼的那句话就是还要在做一次赋值调用

    1.1.2装饰器 - - 语法糖

    import time
    def timer(func):
        def inner():
            start = time.time()
            func()
            end = time.time()
            print(end - start)
        return inner
    
    @timer      # ==> func1 = timer(func1)
    def func1():
        print("in func1")
        time.sleep(0.3)
    
    func1()
    
    # 结果呈现
    in func1
    0.3002743721008301
    

    2,装饰器的使用方式

    2.1 装饰器 - - 带参数的装饰器

    import time
    def timer(func):
        def inner(a):
            start = time.time()
            func(a)
            end = time.time()
            print(end - start)
        return inner
    
    @timer      # ==> func1 = timer(func1)
    def func1(a):
        print("%s in func1" % a)
        time.sleep(0.3)
    
    func1(1)
    
    # 结果呈现
    1 in func1
    0.4000673294067383
    

    2.2 装饰器 - - 带有不定参数的装饰器

    import time
    def timer(func):
        def inner(*args, **kwargs):
            start = time.time()
            func(*args, **kwargs)
            end = time.time()
            print(end - start)
        return inner
    
    @timer      # ==> func1 = timer(func1)
    def func1(a,b):
        print("in func1")
        time.sleep(0.1)
    
    @timer
    def func2(a):
        print("in func 2 and get a:%s" % a)
        time.sleep(0.1)
    
    
    func1("aaaaa", "bbbbb")
    func2("aaa")
    
    # 结果呈现
    in func1
    0.10031294822692871
    in func 2 and get a:aaa
    0.10035037994384766
    

    2.3 装饰器 - - 带返回值的装饰器

    import time
    def timer(func):
        def inner(*args, **kwargs):
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            print(end - start)
            return result
        return inner
    
    @timer      # ==> func1 = timer(func1)
    def func1(a,b):
        print("in func1")
        time.sleep(0.1)
        return "func1 over"
    
    @timer
    def func2(a):
        print("in func 2 and get a:%s" % a)
        time.sleep(0.1)
        return "func2 over"
    
    print(func1("aaaaa", "bbbbb"))
    print("*" * 20)
    print(func2("aaa"))
    
    # 结果呈现
    in func1
    0.10034704208374023
    func1 over
    ********************
    in func 2 and get a:aaa
    0.10026073455810547
    func2 over
    
    

    2.4 装饰器 - - 三层嵌套函数

    def outer(flag):
        def wrapper(func):
           def inner(*args, **kwargs):
               """在函数被调用之前添加的代码"""
               ret = func(*args, **kwargs)
               """在函数被调用之后添加的代码"""
               return ret
           return inner
        return wrapper
    
    @ outer(True)
    def func():
        print("111")
    
    func()
    
    # 结果呈现
    111
    

    2.5 装饰器 - - 多个装饰器装饰同一个函数

    
    def wrapper1(func):     # func --> f
        def innet1():
            print("wrapper1, before func")
            ret = func()      # f
            print("wrapper1, after func")
            return ret
        return innet1
    
    def wrapper2(func):     # func --> inner1
        def innet2():
            print("wrapper2, before func")
            ret = func()      # inner1
            print("wrapper2, after func")
            return ret
        return innet2
    
    
    @wrapper2       # f = wrapper2(f) --> wrapper2(inner1)  == inner2
    @wrapper1       # f = wrapper1(f) == inner1
    def f():
        print("in f")
        return "哈哈哈"
    print(f())         # == inner2()
    
    # 结果呈现
    wrapper2, before func
    wrapper1, before func
    in f
    wrapper1, after func
    wrapper2, after func
    哈哈哈
    

    2.6 查看函数信息的一些方法

    def index():
        """这个一个测试信息"""
        print("test index")
    
    print(index.__name__)   # 查看函数名的方法
    print(index.__doc__)    # 查看函数注释的方法
    
    # 结果呈现
    index
    这个一个测试信息
    

    2.7 完美的装饰器

    from functools import wraps
    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
            print("在被装饰的函数执行之前做的事")
            result = func(*args, **kwargs)
            print("在被装饰的函数执行之后做的事")
            return result
        return inner
    
    @wrapper        # holiday = wrapper(holiday)
    def holiday(day):
        """
        注释:放假
        :param day:
        :return:
        """
        print("全体放假 %s 天" % day)
        return "好开心"
    
    ret = holiday(3)
    print(ret)
    print("*" * 50)
    print(holiday.__name__)
    print(holiday.__doc__)
    
    # 结果呈现
    在被装饰的函数执行之前做的事
    全体放假 3 天
    在被装饰的函数执行之后做的事
    好开心
    **************************************************
    holiday
    
        注释:放假
        :param day:
        :return:
    

    3,开放封闭原则

    1.对扩展是开放的

    • 为什么要对扩展开放呢?
      • 我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。

    2.对修改是封闭的

    • 为什么要对修改封闭呢?
      • 就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。

    装饰器完美的遵循了这个开放封闭原则。

    4,装饰器的主要功能和装饰器的固定结构

    • 装饰器的本质:一个闭包函数
    • 装饰器的作用:在不改变原来函数的调用方式的基础上,在这个函数的前、后添加新的功能

    装饰器的固定格式

    # 基础的装饰器
    def wrapper(func):
       def inner(*args, **kwargs):
           """在函数被调用之前添加的代码"""
           ret = func(*args, **kwargs)
           """在函数被调用之后添加的代码"""
           return ret
       return inner
    def wrapper(func):
       def inner(*args, **kwargs):
           """在函数被调用之前添加的代码"""
           ret = func(*args, **kwargs)
           """在函数被调用之后添加的代码"""
           return ret
       return inner
    
    # 完美的装饰器
    from functools import wraps
    def wrapper(func):
       @wraps(func)
       def inner(*args, **kwargs):
           """在函数被调用之前添加的代码"""
           ret = func(*args, **kwargs)
           """在函数被调用之后添加的代码"""
           return ret
       return inner
    

    5,相关练习题

    5.1 编写装饰器,为多个函数加上记录功能,要求每次调用函数都将被调用的函数名称写入文件

    def log(func):
        def inner(*args, **kwargs):
            with open("hello_world_log", "a", encoding="utf-8") as f:
                f.write(func.__name__ + "
    ")
            result = func(*args, **kwargs)
            return result
        return inner
    
    @log
    def shoplist_add():
        print("增加一件物品")
    
    @log
    def shoplist_del():
        print("删除一件物品")
    
    shoplist_add()
    shoplist_del()
    

    5.2 编写下载网页内容的函数,要求功能是:用户传入一个 url,函数返回下载页面的结果

    from urllib.request import urlopen
    def get(url):
        code = urlopen(url).read
        return code
    
    result = get("https://www.baidu.com")
    print(result)
    

    5.3为上个题目写装饰器,实现缓存网页内容的功能:

    具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后

    import os
    from urllib.request import urlopen
    
    def cache(func):
        def inner(*args, **kwargs):
            if os.path.getsize("hello_world_web_cache"):
                with open("hello_world_web_cache","rb") as f:
                    return f.read()
            ret = func(*args, **kwargs)
            with open("hello_world_web_cache","wb") as f:
                f.write(b"***" + ret)
            return ret
        return inner
    
    @cache
    def get(url):
        code = urlopen(url).read()
        return code
    
    result = get("https://www.baidu.com")
    print(result)
    
  • 相关阅读:
    DesignPattern系列__10单例模式
    DesignPattern系列__09设计模式概述
    DesignPattern系列__08UML相关知识
    DesignPattern系列__07合成复用原则
    DesignPattern系列__06迪米特原则
    爬取猫眼电影top100电影
    安卓微信对接H5微信支付出现“商家参数有误,请联系商家解决”的问题处理
    python 通过使用pandas的实现的Excel的批量转换CSV文件的处理
    输入一个字符串,判断字符串中最大对称字串的长度
    面向对象六大设计原则(转载)
  • 原文地址:https://www.cnblogs.com/xiaoqshuo/p/9669083.html
Copyright © 2020-2023  润新知