装饰器总结

  1. 开放封闭原则

    • 对拓展是开放的,允许代码拓展,添加新功能
    • 对修改是封闭的,不能修改函数的源码和调用方式
  2. 装饰器

    • 在不改变原被装饰函数的源代码以及调用方式的前提下,为其添加额外的功能
    # 版本一,测试每个函数都要写一遍代码.
    import time
    def func1():
        time.sleep(2)    # 暂停2秒
        print('测试延迟')
    time1 = time.time()  # 返回的格林尼治时间,是此时此刻距离1970年1月1日0时0分0秒的时间秒数.也叫时间戳
    func1()
    time2 = time.time()
    print(time2 - time1)
    
    # 版本二,只能测试特定的函数
    import time
    def func1():
        time.sleep(2)    
        print('测试延迟')
    
    def ceshi():
        time1 = time.time()  
        func1()
        time2 = time.time()
        print(time2 - time1)
    ceshi()
    
    # 版本三,虽然没有改变原函数代码,但是改变了执行方式,不符合开放封闭原则
    import time
    def func1():
        time.sleep(2)    
        print('测试延迟')
    def ceshi(func):
        time1 = time.time() 
        func()
        time2 = time.time()
        print(time2 - time1)
    ceshi(func1)
    
    # 版本四,实现真正的开放封闭原则:装饰器
    import time
    def func1():
        time.sleep(2)
        print('测试延迟')
    
    def timer(func):
        def ceshi():
            time1 = time.time()
            func()
            time2 = time.time()
            print(time2 - time1)
        return ceshi
    func1 = timer(func1)
    func1()
    
    # 带返回值的装饰器
    import time
    def func1():
        time.sleep(2)
        print('测试延迟')
        return '测试成功'
    
    def timer(func):
        def ceshi():
            time1 = time.time()
            ret = func()
            time2 = time.time()
            print(time2 - time1)
            return ret
        return ceshi
    func1 = timer(func1)
    print(func1())
    
    # 被装饰函数带参数的装饰器
    import time
    def func1(name):
        time.sleep(2)
        print(f'{name}测试延迟')
        return f'{name}测试成功'
    
    def timer(func):
        def ceshi(name):
            time1 = time.time()
            ret = func(name)
            time2 = time.time()
            print(time2 - time1)
            return ret
        return ceshi
    func1 = timer(func1)
    print(func1('太上老君'))
    
    # 被装饰函数不定参数的装饰器
    import time
    def func1(*args, **kwargs):
        time.sleep(2)
        print(f'{args}测试延迟')
        print(f'{kwargs}测试延迟')
        return f'{args, kwargs}测试成功'
    
    def timer(func):
        def ceshi(*args, **kwargs):
            time1 = time.time()
            ret = func(*args, **kwargs)
            time2 = time.time()
            print(time2 - time1)
            return ret
        return ceshi
    func1 = timer(func1)
    print(func1('太上老君', '元始天尊', 我叫='通天教主'))
    
    # 标准的装饰器:语法糖
    import time
    def timer(func):
        def ceshi(*args, **kwargs):
            time1 = time.time()
            ret = func(*args, **kwargs)
            time2 = time.time()
            print(time2 - time1)
            return ret
        return ceshi
    @timer   #  相当于 func1 = timer(func1),没有特殊意义,为了简单化
    def func1(*args, **kwargs):
        time.sleep(2)
        print(f'{args, kwargs}测试延迟')
        return f'{args, kwargs}测试成功'
    print(func1('太上老君', '元始天尊', 我叫='通天教主'))
    
    # 带参数的装饰器
    # 准备好qq文件用于保存qq密码,tiktok用于保存抖音密码
    def get_dic(file_name): # 获取密码库
        dic = {}
        with open(file_name, mode='r', encoding='utf-8') as f1:
            for line in f1:
                username, psw = line.strip().split('|')
                dic[username] = psw
        return dic
    
    def login(dic):   # 3次登陆功能
        time = 3
        while time > 0:
            username = input('请输入用户名:').strip()
            psw = input('请输入密码:').strip()
            if dic.get(username) == psw:
                return True
            time -= 1
        return False
    
    def wrapper_out(file_name):  # 装饰器本体
        def wrapper(func):
            def inner():
                dic = get_dic(file_name) # 获取相应的密码库
                if login(dic):  # 调用登陆函数
                    ret = func()
                    return ret
                return False
            return inner
        return wrapper
    
    @wrapper_out('qq')
    def qq():
        print('欢迎登陆QQ~~~~')
        return '登陆成功'
    print(qq())
    
    @wrapper_out('tiktok')
    def tiktok():
        print('欢迎访问抖音~~~')
        return '登陆成功'
    print(tiktok())
    
    # 多个装饰器装饰同一个函数的运行顺序
    def w1(func):  # func == 原函数text
        def inner():
            print('正在运行w1.inner....1')  # 2
            func()  # 原函数text()
            print('正在运行w1.inner....2')  # 4
        return inner
    
    def w2(func):  # func == w1.inner
        def inner():
            print('正在运行w2.inner....1')  # 1
            func()  # w1.inner()
            print('正在运行w2.inner....2') # 5
        return inner
    @w2  #  text = w2(text)    后面的text是w1.inner, 前面的text == w2.inner
    @w1  #  text = w1(text)    后面的text是原函数, 前面的text == w1.inner
    def text():
        print('正在运行被装饰的函数...')  # 3
    
    text()  # w2.inner()
    
posted @ 2019-06-24 16:01  怀心抱素  阅读(251)  评论(0编辑  收藏  举报