python装饰器

python装饰器--开放封闭原则

知识点回顾

# *args **kwargs
def wrapper(*args,**kwargs): # 接受(形参) args=(1,2,3) kwargs={'a':1,'b':2}
    index(*args,**kwargs)	# 打散(实参)
    						# index(*(1,2,3),**{'a':1,'b':2})
        					# index(1,2,3,a=1,b=2) 原封不动的传给index
wrapper(1,2,3,a=1,b=2)

1 ----> 5装饰器无参

6 ----> 7装饰器有参

1. 原函数无参的装饰

在不改变原代码上,添加新的功能

装饰器需要定义在原函数前面,并且命名要明确

import time

'''装饰函数'''
def timmer(func):  # 1.传入函数名
    def wrapper():
        start = time.time()
        func()  # 2.执行传入函数
        end = time.time()
        print(end - start)

    return wrapper  # 3.返回了函数名


'''原来代码'''
def index():
    time.sleep(3)
    print('index无参数')


'''index旧瓶新装'''
index = timmer(index)  # 4.等于把旧index传入到wrapper函数中了
# 4-1 新的index = warpper内存地址
index()  # 5.新的index,其实调用-->wrapper()

1.1 语法糖

​ 语法糖:让你开心的事

import time


def timmer(func):
    def wrapper():
        start = time.time()
        func()
        end = time.time()
        print(end - start)

    return wrapper


@timmer  # 1.语法糖其实是封装了上面[4]的写法,使其更加直观->@装饰器名
def index():
    time.sleep(3)
    print('index无参数')


index()  # 2.新的index,其实调用-->wrapper()

2. 原函数有参的装饰器

import time


def timmer(func):
    def wrapper(*args, **kwargs):  # 1.传入不确定参数
        start = time.time()
        func(*args, **kwargs)  # 2.把参数传给原函数(⚠️一定要带 * 号)
        end = time.time()
        print(end - start)
    return wrapper


@timmer
def index(x, y):
    time.sleep(3)
    print('index %d %d' % (x, y))


index(1, 2)
index 1 2
3.014557123184204

3.原函数有返回值的装饰器

import time


def timmer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)  # 2.res接受原函数返回值
        end = time.time()
        print(end - start)
        return res  # 3.在装饰器末尾加上return res
    return wrapper


@timmer
def index(x, y):
    time.sleep(3)
    return x + y  # 1.原函数有返回值


res = index(1, 2)  # 4.通过装饰器后拿到了返回值

4.原函数执行多个装饰器执行

多个装饰器是从底下向上运行的

def wrapper1(func):
    def inner1(*args, **kwargs):
        print("wrapper1 装饰函数前 可以做一些事 ")
        ret = func(*args, **kwargs)
        print("wrapper1 装饰函数后 可以做一些事 ")
        return ret
    return inner1

def wrapper2(func):
    def inner2(*args, **kwargs):
        print("wrapper2 装饰函数前 可以做一些事 ")
        ret = func(*args, **kwargs)
        print("wrapper2 装饰函数前 可以做一些事 ")
        return ret
    return inner2

@wrapper2		# 2.
@wrapper1		# 1. 
def func():
    print("我是函数,我被两个装饰器装饰")
    return "函数 返回值"

ret = func()
print(ret)
# ----------------------------运行结果------------------------
# wrapper2 装饰函数前 可以做一些事
# wrapper1 装饰函数前 可以做一些事
# 我是函数,我被两个装饰器装饰
# wrapper1 装饰函数后 可以做一些事
# wrapper2 装饰函数前 可以做一些事
# 函数 返回值

5.伪装的更像原函数

def timmer(func):
    def wrapper(*args,**kwargs)
    	res =func(*args,**kwargs)
    	return res
    	wrapper.__name__ = func.__name__ 	# 3.需要把原函数的内置属性赋值过来
        wrapper.__doc__ = func.__doc__		# 4.不可能一个个的写完
        ......
    retrun wrapper

@timmer
def index(x,y):
    '''这是一个文档'''
    print(x,y)
    
print(index.__name__)  ---->index			# 1.伪装原函数
print(index.__doc__)---->这是一个文档

5-1. from functools import wraps

⚠️⚠️⚠️一定要记住:wraps(func)

from functools import wraps  # 1.wrpas(func)就是装饰器


def timmer(func):
    @wraps(func)  # 2.就是将原函数的内置属性拿过来
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        return res

    return wrapper


@timmer
def index(x, y):
    '''这是一个文档'''
    print(x, y)


print(index.__name__)
print(index.__doc__)
index
这是一个文档

6.了解装饰器@作用---为7做铺垫

@名字 --> home = 名字(home)
def home():
    pass

@名字()--> 先执行名字(),返回值---> home = 返回值(home)
def home():
    pass

7.有参的装饰器(需要掌握)

  • 装饰器其实用的wrapper函数
  • 因为deco和wrapper中不能传入参数了
  • 所有外面在套一层auth
from functools import wraps


def auth(a_type):  # 1.外层在包一层函数,接受参数
    def deco(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if a_type == 'XXX1':  # 2,接受的参数来判断运行那个代码
                print('XXX1')
                res = func(*args, **kwargs)
                return res
            elif a_type == 'XXX2':
                print('XXX2')
                res = func(*args, **kwargs)
                return res
            elif a_type == 'XXX3':
                print('XXX3')
                res = func(*args, **kwargs)
                return res
            else:
                print('a_type类型错误')

        return wrapper

    return deco  # 3.返回函数deco


@auth('XXX1')  # 4.使用语法糖添加类型【可变的】
def index1(x, y):
    print(x + y)


@auth('XXX2')  # 5.@名字()--> 先执行名字(),返回值deco-->[因为【3】return deoc]
def index2(x, y):
    print(x + y)


@auth('XXX3')  # 6.返回值已经是deco,再执行@deco,此时参数已经被传入内部了
def index3(x, y):
    print(x + y)


if __name__ == '__main__':
    index1(1, 2)
XXX1
3
posted @ 2023-01-09 00:14  lxd670  阅读(18)  评论(0编辑  收藏  举报