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
    哈哈哈
    '''
    用途:
    记录用户的登录情况
    计算这个函数的执行时间



  • 相关阅读:
    how to uninstall devkit
    asp.net中bin目录下的 dll.refresh文件
    查找2个分支的共同父节点
    Three ways to do WCF instance management
    WCF Concurrency (Single, Multiple, and Reentrant) and Throttling
    检查string是否为double
    How to hide TabPage from TabControl
    获取当前系统中的时区
    git svn cygwin_exception
    lodoop打印控制具体解释
  • 原文地址:https://www.cnblogs.com/hanfe1/p/10496894.html
Copyright © 2011-2022 走看看