• Python学习日记(九) 装饰器函数


    1.import time

      a.time.time()

      获取到当前的时间,返回值为浮点型

    import time
    print(time.time())  #1565422783.6497557

      b.time.sleep()

      让程序执行到这个位置暂停一会

    import time
    start = time.time()
    time.sleep(0.5)
    print('hello world!')
    end = time.time()
    print(end - start)  #0.5000286102294922

    2.装饰器函数

    开发原则:开放封闭原则

    装饰器的作用:在不改变原函数的情况下,在函数的前后添加功能

    装饰器的本质:闭包函数

    当想要知道一个程序执行的时间

    import time
    start = time.time()
    time.sleep(0.5)
    print('hello world!')
    end = time.time()
    print(end - start)  #0.5000286102294922

    再将里面的功能单独拉出来变成一个函数

    import time
    def func():
        time.sleep(0.5)
        print('hello world!')
    def timer(func):
        start = time.time()
        func()
        end = time.time()
        print(end - start)
    timer(func)     #hello world!
                    #0.5000286102294922

    将timer变成一个简单的装饰器

    import time
    def func():                 #被装饰的函数
        time.sleep(0.5)
        print('hello world!')
    def timer(func):            #装饰函数
        def inner():
            start = time.time()
            func()
            end = time.time()
            print(end - start)
        return inner            #回传inner函数的内存地址
    get_inner = timer(func)     #后者得到的是inner的内存地址再赋值给get_inner
    get_inner()                 #hello world!
                                #0.5000286102294922

    执行步骤:

    开放封闭原则:开放指的是对扩展开放,封闭指的是对修改封闭

    语法糖:@装饰器函数名  可以替代下面的写法

    装饰带一般参数且有返回值函数的装饰器

    import time
    def wrapper(f):     #装饰器函数
        def inner(x):
            res = f(x)
            return res
        return inner
    @wrapper            #相当于 fuc = wrapper(fuc)
    def fuc(var):       #被装饰的函数
        print(var,'Python')
        return False
    res = fuc('Hello')
    print(res)

    装饰带万能参数的函数装饰器

    import time
    def wrapper(f):             #装饰器函数
        def inner(*args,**kwargs):
            start = time.time()
            ret = f(*args,**kwargs)
            end = time.time()
            print(end - start)
            return ret
        return inner
    @wrapper        #相当于 fuc = wrapper(fuc)
    def fuc(a,b,c,d,e = 5):     #被装饰的函数
        time.sleep(0.5)
        print(a,b,c,d,e)
        return e
    print(fuc(1,2,3,4,'Python'))

    总结:装饰器的模板

    import time
    def wrapper(f):
        def inner(*args,**kwargs):
            #在被装饰函数之前要做的事
            res = f(*args,**kwargs)
            #在被装饰函数之后要做的事
            return res
        return inner
    @wrapper
    # func = wrapper(func)
    def func():            #被装饰的函数
        return
    ret = func()
    print(ret)

    查看函数信息的方法

    def fuc(var):
        '0123456789'
        print(var,'Python')
        return False
    print(fuc.__name__) #fuc        主要用于查看函数名
    print(fuc.__doc__)  #0123456789    主要用于查看函数的注释

    我们在使用fuc()函数的时候实际上我们调用的是inner()函数,如果我们要在不修改原函数的前提下拿到原函数的信息,只需要将inner()函数变成一个装饰器:

    def wrapper(f):
        def inner(*args,**kwargs):
            ret = f(*args,**kwargs)
            return ret
        return inner
    @wrapper
    def fuc():
        print('Python')
        return True
    print(fuc())
    print(fuc.__name__)     #inner 这里调用的是inner函数

    修改后:

    from functools import wraps
    def wrapper(f):
        @wraps(f)
        def inner(*args,**kwargs):
            ret = f(*args,**kwargs)
            return ret
        return inner
    @wrapper
    def fuc():
        print('Python')
        return True
    print(fuc())
    print(fuc.__name__)     #fuc 这里就改回调用的函数名是fuc

     带参数的装饰器

    如果许多函数都使用了同一个装饰器,那么它将需要一个布尔值作为参数来作为开关控制它们的使用

    FLAGE = False
    def wrapper_ctrl(flag):
        def wrapper(fuc):
            def inner(*args,**kwargs):
                if flag:
                    print('装饰器已开启...')
                    ret = fuc()
                    return ret
                else:
                    print('装饰器已关闭...')
            return inner
        return wrapper
    
    @wrapper_ctrl(FLAGE)
    def function1():
        print('aaaaaaa')
    
    @wrapper_ctrl(FLAGE)
    def function2():
        print('bbbbbbb')
    
    @wrapper_ctrl(FLAGE)
    def function3():
        print('ccccccc')
    
    function1()     #装饰器已关闭...
    function2()     #装饰器已关闭...
    function3()     #装饰器已关闭...

    多个装饰器装饰一个函数

    def wrapper1(fuc):  #2Step:fuc->f
        def inner1(*args,**kwargs):
            print('wrapper1在装饰该函数前要做的事...')     #12Step:print
            fuc(*args,**kwargs)    #13Step:这里的fuc就是f 因为第二步已经传进来了
            print('wrapper1在装饰该函数后要做的事...')     #15Step:print
        return inner1   #3Step:传回inner1
    
    def wrapper2(fuc):  #6Step:fuc->inner1
        def inner2(*args,**kwargs):
            print('wrapper2在装饰该函数前要做的事...')     #10Step:print
            fuc(*args,**kwargs)     #11Step:这里的fuc()实际上是inner1()
            print('wrapper2在装饰该函数后要做的事...')     #16Step:print
        return inner2   #7Step:返回inner2
    @wrapper2   #5Step:f = wrapper2(f) 这里的f是inner1 即 f = wrapper2(inner1)
                #8Step:f = inner2
    @wrapper1   #1Step:f = wrapper1(f)
                #4Step:f = inner1
    #装饰器会找离它最近的函数 离这个函数最近的装饰器会先执行
    def f():
        print('abcdefg')        #14Step:print
    f() #9Step:这里调用的f()实际上是inner2()
    
    '''执行结果'''
    # wrapper2在装饰该函数前要做的事...
    # wrapper1在装饰该函数前要做的事...
    # abcdefg
    # wrapper1在装饰该函数后要做的事...
    # wrapper2在装饰该函数后要做的事...

    流程图:

    3.和装饰器相关的案例

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

    FLAG = False        
    def login(f):
        def inner(*args,**kwargs):
            global FLAG     
            if FLAG:    #如果已经登入成功
                f(*args,**kwargs)
            else:
                username = input('请输入用户名:')
                password = input('请输入密码:')
                if username.strip() == 'JANE' and password.strip() == '123456':
                    FLAG = True
                    print('登入成功!')
                    f(*args,**kwargs)
                else:
                    print('登入失败!')
        return inner
      
    get_name('JANE')
    get_ID()

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

    def log(f):
        def inner(*args,**kwargs):
            with open('log.txt',mode = 'a',encoding='utf-8') as fileStream:
                fileStream.write(f.__name__ + '
    ')
            f(*args,**kwargs)
        return inner
    @log
    def get_name():
        print('Your username is JANE')
    @log
    def get_ID():
        print('Your user ID is 110123')
    get_ID()
    get_name()
    get_ID()

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

    from urllib.request import urlopen
    def get(url):
        html = urlopen(url).read()
        return html
    ret = get('http://www.baidu.com')
    print(ret)
    #<bound method HTTPResponse.read of <http.client.HTTPResponse object at 0x00000000073BC860>>

    d.为c编写装饰器,实现缓存网页内容的功能,主要功能:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则就去下载,然后存到文件中

    import os
    from urllib.request import urlopen
    def cache(func):
        def inner(*args,**kwargs):
            if os.path.getsize('web_cache'):    #如果不为0 就是True 从文件中找到源码
                with open('web_cache','rb') as f:
                    return f.read()
            ret = func(*args,**kwargs)           #取得网页的源码
            with open('web_cache','wb') as f:
                f.write(b'*******' + ret)       #若文件没有网页源码则写入新标志和源码
            return ret
        return inner
    @cache
    def get(url):
        code = urlopen(url).read()
        return code
    end = get('http://www.baidu.com')
    print(end)
    end = get('http://www.baidu.com')
    print(end)
    end = get('http://www.baidu.com')
    print(end)
  • 相关阅读:
    python3.5 安装mysqlclient
    python mysqlclient安装失败 Command "python setup.py egg_info" failed with error code 1
    python mysqlclient安装失败 Command "python setup.py egg_info" failed with error code 1
    JUC-多线程锁
    JUC-线程间通信
    JUC-LOCK接口
    JUC-JUC是什么?
    Zookeeper
    Mac 安装IDEA 2018.3 版本
    MyISAM和innoDB
  • 原文地址:https://www.cnblogs.com/Fantac/p/11332275.html
Copyright © 2020-2023  润新知