zoukankan      html  css  js  c++  java
  • python全栈闯关--11-装饰器初识

    1、装饰器形成

    当不想修改原函数,未函数前后添加功能时,就可以使用装饰器,在函数前后增加功能。

    装饰器的初始形成

    import time
    
    def timer(f):
        def inner():
            print("我是装饰器,我来装饰了!!!")
            start = time.time()
            f()
            end = time.time()
            print(start - end)
        return inner  # 返回inner由于f实现了闭包,直接调用了程序
    
    def func():
        time.sleep(1)
        print("我是小鱼,要作作作。。。有本事来装饰我!")
    
    # 通过inner返回,在func前后进行了函数的功能的扩展
    t = timer(func)
    t()  # 虽然实现了功能,但是函数的调用名修改了
    
    # 为了不改变调用名,可以赋值给func
    func = timer(func)
    func()  # 通过装饰器,实现了不修改函数名的装饰

    语法糖

    在函数前面加,加上@函数名,就可以实现装饰器,叫做语法糖

    def timer(f):
        def inner():
            print("我是装饰器,我来装饰了!!!")
            start = time.time()
            f()
            end = time.time()
            print(start - end)
        return inner  # 返回inner由于f实现了闭包,直接调用了程序
    
    @timer
    def func():
        time.sleep(1)
        print("我是小鱼,要作作作。。。有本事来装饰我!")

    2、带参数和返回值的装饰器

    import time
    
    def timer(f):
        def inner(a,b):  # inner接收传入的参数
            print("我是装饰器,我来装饰了!!!")
            start = time.time()
            ret = f(a,b)
            end = time.time()
            print(start - end)
            return  ("我是装饰器的返回值!!!",start - end)  # 在闭包内部,实现返回值
        return inner  # 返回inner由于f实现了闭包,直接调用了程序
    
    @timer
    def func(a,b):
        time.sleep(1)
        print("我是小鱼,要作作作。。。有本事来装饰我!")
        print("a=%s,b=%s" % (a,b))
    
    ret = func(1,2)  # 参数相当于传递给inner
    print(ret)

    执行顺序

    3、传递任意参数的装饰器

    通过*args和**kwargs传递任意参数

    def warpper(f):
        def inner(*args, **kwargs):
            ret = f(*args, **kwargs)
            return ret
        return inner
    
    @warpper
    def func(*args, **kwargs):  #*和**打散
        print("我是被装饰的函数!")
        print(args)
        print(kwargs)
    
    func()  # 传空参数
    func(1,2,3,4,b=1, a=2)  # 传任意参数
    dic1 = {"a":1, "b":2}
    func(*(1,2,3,4),**dic1)  # 打散传递

    4、参数位置随感

    个人观察结论:*是按顺序打散,形参位置:*args中,args打散后为1 2 3 4,所以args为(1,2,3,4)

    def outer(*args):
        print(args)  # (1, 2, 3, 4)
        print(*args)  # 1 2 3 4  元祖被打散
        def inner(*args):
            print('innner', args)
        inner(*args)  # 打散传入inner(1,2,3,4)
    
    outer = outer(1,2,3,4)

    5、warps

    函数的__doc__和__name__可以查看函数的说明和名字。

    装饰器后,函数名和名字都变为装饰器的内部函数

    def warpeer(f):
        def inner(*args, **kwargs):
            '''
            this is warpper inner
            :param args:
            :param kwargs:
            :return:
            '''
            print("this is innser")
            ret = f(*args, ** kwargs);
            return ret
        return inner
    
    @warpeer
    def func():
        print("this is func")
    
    print(func.__name__)
    print(func.__doc__)

     加上wraps后,可以识别到函数自己的doc和name

    from functools import wraps
    
    def warpeer(f):
        @wraps(f)
        def inner(*args, **kwargs):
            '''
            this is warpper inner
            :param args:
            :param kwargs:
            :return:
            '''
            print("this is innser")
            ret = f(*args, ** kwargs);
            return ret
        return inner
    
    @warpeer
    def func():
        '''
        this is func doc
        :return:
        '''
        print("this is func")
    
    print(func.__name__)
    print(func.__doc__)

     

    6、练习

    # 1.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),
    # 要求登录成功一次,后续的函数都无需再输入用户名和密码
    
    uname = "小鱼"
    upwd = "qwe"
    LOGTYPE = False
    
    
    def login(func):
        def in_login():
            global LOGTYPE
            # print(LOGTYPE)
            if LOGTYPE:
                # print(LOGTYPE)
                func()
                return
            username = input("请输入用户名:")
            userword = input("请输入密码:")
            if username.strip() == uname and userword.strip() == upwd:
                ret = func()
                LOGTYPE = True
                return ret
            else:
                print("用户名或者密码错误!")
            pass
    
        return in_login
    
    
    @login
    def shoplist_add():
        print("增加一件商品!")
    
    
    @login
    def shoplist_del():
        print("删除一件商品!")
    
    
    shoplist_add()
    shoplist_del()
    # 1.编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
    # 2.为题目1编写装饰器,实现缓存网页内容的功能:
    # 具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
    
    import os
    from urllib.request import urlopen as uop
    
    def catche(fun):
        def in_c(*args, **kwargs):
            file = "catche.txt"
            if not os.path.exists(file):
                with open(file, 'wb') as f:
                    f.write("")
            if os.path.getsize(file) :
                with open(file, 'rb') as f:
                    return f.read()
            else:
                ret = fun(*args, **kwargs)
                with open(file, 'wb') as f:
                    f.write(b'****catche***' + ret)
                return ret
        return in_c
    
    @catche
    def get_url(url):
        ret = uop(url).read()
        return ret
    
    
    print(get_url("http://www.baidu.com"))
    print(get_url("http://www.baidu.com"))
  • 相关阅读:
    MySQL系列(二)
    MySQL系列(一)
    RabbitMQ的安装部署
    RabbitMQ原理介绍
    消息中间件metaq
    消息中间件之zookper安装部署
    ZooKeeper基本原理
    消息中间件剖析
    了解Node.js
    windows下使用Git
  • 原文地址:https://www.cnblogs.com/zxw-xxcsl/p/11704879.html
Copyright © 2011-2022 走看看