zoukankan      html  css  js  c++  java
  • python之路day12装饰器的进阶

    装饰器
    # 开发原则:开发封闭原则
    # 装饰器的作用:在不改变原函数的调用函数下,在函数的前后添加功能。
    # 装饰器的本质:闭包函数
    import time
    
    def timmer(f):  #func     #timmer就是一个装饰器函数
        def inner():
            start = time.time()
            f() #用外部函数的变量f 是一个闭包  f()就是被装饰的函数
            end = time.time()
            print(end-start)
        return inner #返回内部函数的名字(注意)
    
    
    @timmer   #语法糖 @装饰器函数名,下面必须是被装饰的函数
    def func(): #被装饰的函数
        time.sleep(0.01)
        print('大魔王法克儿')
    # func=timmer(func) #有了语法糖这一句就不用写了
    func()  #相当于是inner()

    args:接受*就是聚合,调用加*就是打散

    *args:接受*就是聚合,调用加*就是打散
    # *args:接受*就是聚合,调用加*就是打散
    def func(*args): #站在形参的角度上,给变量加上*,就是组合所有传来的值
    print(args) #(1, 2, 3, 4, 5)
    print(*args) #1 2 3 4 5


    func(1,2,3,4,5) #(1, 2, 3, 4, 5)

    执行顺序  

    装饰器想当与一个中介,

     wraps

    Python装饰器(decorator)在实现的时候,有一些细节需要被注意。例如,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变)。这样有时候会对程序造成一些不便,例如笔者想对flask框架中的一些函数添加自定义的decorator,添加后由于函数名和函数的doc发生了改变,对测试结果有一些影响。

    所以,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和docstring。

    def wahaha():
        '''
        一个函数
        :return:
        '''
    
        print('娃哈哈')
    
    print(wahaha.__name__) #wahaha
    def wrapper(func):  #func=holidy
        def inner(*args,**kwargs):
            print('在被装饰函数之前执行')
            ret = func(*args,**kwargs)  #这个就是被装饰的函数
            print('在被装饰函数之后执行')
            return ret
        return inner  #inner = holidy
    
    @wrapper #holidy=wrapper(holidy)  #调用wrapper,将holidy传进去,结果就是inner=holidy
    def holidy(day):
        print('放假%s天'% day)
        return '返回的是这里'
    ret = holidy(3) #inner()
    print(ret)
    from functools import wraps
    def wrapper(func):  #func=holidy
        @wraps(func) #
        def inner(*args,**kwargs):
            print('在被装饰函数之前执行')
            ret = func(*args,**kwargs)  #这个就是被装饰的函数
            print('在被装饰函数之后执行')
            return ret
        return inner  #inner = holidy
    
    @wrapper #holidy=wrapper(holidy)  #调用wrapper,将holidy传进去,结果就是inner=holidy
    def holidy(day):
        '''holidy._doc_出现的内容'''
        print('放假%s天'% day)
        return '返回的是这里'
    
    
    print(holidy.__name__)
    print(holidy.__doc__)
    
    ret = holidy(3) #inner()
    # print(ret)

    作业

    # 1、编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),
    # 要求登录成功一次,后续的函数都无需再输入用户名和密码。

    FALG = False #定义一个全局变量
    def login(f):
        def inner(*args,**kwargs):
            global FALG
            if FALG == True:
                ret= f(*args,**kwargs)
                return ret
            else:
                '''登录程序'''
                username = input('请输入你的账号:')
                password = input('请输入你的密码:')
                li=[]
                with open('The user data',mode='r+',encoding='utf-8') as f1:
                    for line in f1:
                        li.append(line)
    
                if username.strip() == li[0].strip() and password.strip() == li[1].strip():
                    FALG =True  #全局变量=True
                    ret = f(*args, **kwargs)
                    return ret
    
                else:
                    print('用户名或密码错误,请重试')
    
        return inner
    
    @login
    def shoplist_add():
        print('增加一件物品')
        return 1
    
    def shoplist_del():
        print('减少一件物品')
        return 2
    
    ret=shoplist_add()
    ret=shoplist_del()
    print(ret)
    2、编写装饰器,为多个函数加上记录调用的功能,要求每次调用都将被调用的函数名称写入文件内
    from functools import wraps
    def log_record(f):
        # @wraps(f)
        def inner(*args,**kwargs):
            print('--start---')
            ret=f(*args,**kwargs)
            print('--record---')
    
            with open('log_record',mode='a+',encoding='utf-8') as f1:
                f1.write(f.__name__)
            return ret
    
        return inner
    @log_record
    def fun1():
        return 1
    ret =fun1()
    print(ret)
    
    @log_record
    def fun2():
        return 2
    
    ret =fun2()
    print(ret)
    进阶
    1、编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
    import urllib
    from urllib.request import urlopen
    
    def get(url):
        code = urlopen(url).read()
        print(code)
    
    ret=get('https://www.baidu.com/')
    print(ret)
    2、为题目1编写装饰器,实现缓存网页中内容的功能具体:实现下载的页面存放于文件中,如果文件中有值,就从文件中取,否则取下载存到文件中
    import urllib
    from urllib.request import urlopen
    import os
    def cache(f):
        def inner(*args,**kwargs):
    
            if os.path.getsize('web_cache'): #如果有这个文件
                with open('web_cache', mode='rb') as f1:
                    return f1.read()
            else:
                ret=f(*args,**kwargs)
                with open('web_cache', mode='wb') as f1:
                    f1.write(b'@@@@@@'+ret)
                return ret
        return inner
    
    @cache
    def get(url):
        code = urlopen(url).read()
        return code
    
    ret=get('https://www.baidu.com/') #第一次是从网站读出来的
    print(ret)
    ret=get('https://www.baidu.com/')#二次是从自己文件中读出
    print(ret)
    ret=get('https://www.baidu.com/')#三次是从自己文件中读出
    print(ret)

    装饰器的进阶(带参数的装饰器,多个装饰器装饰一个函数)

    带参数的装饰器

    #500个函数
    import time
    FALGE=True  #用flag判断
    def timmer_out(flag): #flag 只是形参,参数是谁无所谓  #最外边的一层只是为了把FALGE传进,其他的并没有改变
        def timmer(func):
            def inner(*args,**kwargs):
                if flag:  #如果flag 为true 则执行装饰器里计算时间的功能
    
                    start = time.time()
                    ret=func(*args,**kwargs)
                    end =time.time()
                    print(end - start)
                    return ret
                else:
                    ret = func(*args, **kwargs)
                    return ret
            return inner
        return timmer
    
    #
    @timmer_out(FALGE)  #先执行 timmer_out(FALGE)-->返回timmer给timmer_out,此时其实就为@timmer
    def wahaha():
        time.sleep(0.1)
        print('wahhhhhhhhh')
    
    
    @timmer_out(FALGE)
    def xiaoyi():
        time.sleep(0.2)
        print('xiaoyiyiyiyi')
    
    
    #FLAGE=false #在这里可以控制FLAGE
    wahaha()
    xiaoyi()


    多个装饰器装饰一个函数 (俄罗斯套娃,一层一层)
    def wrapper1(func):
        def inner():
            print('wrapper1,before func')
            func()
            print('wrapper1,after func')
        return inner
    
    def wrapper2(func):
        def inner():
            print('wrapper2,before func')
            func()
            print('wrapper2,after func')
        return inner
    
    @wrapper2
    @wrapper1  #靠近函数的这个装饰器先执行
    def f():
        print('in f')
    
    f()
    #结果
    '''
    wrapper2
    wrapper1
    in f
    wrapper1
    wrapper2
    '''

    执行顺序:

    ps:

    def wrapper1(func):
        def inner():
            print('wrapper1,before func')
            ret=func()
            print('wrapper1,after func')
            return ret
        return inner
    
    def wrapper2(func):
        def inner():
            print('wrapper2,before func')
            ret = func()
            print('wrapper2,after func')
            return ret
    
        return inner
    
    @wrapper2
    @wrapper1  #靠近函数的这个装饰器先执行
    def f():
        print('in f')
        return '哈哈哈'
    print(f())
    #结果(但是结果是从上至下,可以理解为套娃)
    '''
    wrapper2,before func
    wrapper1,before func
    in f
    wrapper1,after func
    wrapper2,after func
    哈哈哈
    '''
    
    # ps:
    def f2():
        print('in f')
        return '哈哈哈'
    print(f2())
    '''
    in f
    哈哈哈
    '''
    用途:
    记录用户的登录情况
    计算这个函数的执行时间



  • 相关阅读:
    第五届蓝桥杯JavaB组省赛真题
    第五届蓝桥杯JavaB组省赛真题
    第五届蓝桥杯JavaA组省赛真题
    第五届蓝桥杯JavaA组省赛真题
    第五届蓝桥杯JavaA组省赛真题
    第五届蓝桥杯JavaA组省赛真题
    FastReport的交叉表实际使用的一个例子
    成熟的人首先得明白自己是个什么样的人
    ACL 我为什么要发明一个轮子?
    利润就是被存储的,接到指令就可以被使用的劳动时间
  • 原文地址:https://www.cnblogs.com/hanfe1/p/10496894.html
Copyright © 2011-2022 走看看