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"))
原文地址:https://www.cnblogs.com/zxw-xxcsl/p/11704879.html