第二十九篇 装饰器

第二十九篇 装饰器

一、无参装饰器

1.什么是装饰器

  • 1.修改或增加其他函数的功能的函数
  • 2.需要注意的是:
    • 1.装饰器本身是可以被任意调用的对象
    • 2.装饰的对象也可以是任意可调用的对象

2.为什么需要装饰器

当我们需要修改程序的某个功能,但是不想修改函数或对象的调用方法时,这时就可以使用装饰器。由于软件的维护需要遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能是开放的

3.如何使用装饰器

  • 1.装饰器的实现必须遵循两大原则(装饰器就是在遵循以下两个原则的前提下为被装饰对象添加新功能):

    # 假设源码是一个延时函数
    import time
    def timesleep():
        time.sleep(1)
        print('睡眠一秒')
    
    • 1.不修改被装饰对象的源代码
    # 改源码增加功能
    import time
    def counttime():
        start = time.time()
        time.sleep(1)
        print('睡眠一秒')
        end = time.tiem()
    	pirnt(end-start)
    
    • 2.不修改被装饰对象的调用方法
    # 改变调用方法
    import time
    def timesleep():
        time.sleep(1)
        print('睡眠一秒')
    
    def counttime():
        start = time.time()
        timesleep()
        end = time.tiem()
    	pirnt(end-start)
    
  • 利用装饰器实现

# 源码
import time
def timesleep():
    time.sleep(1)
    print('睡眠一秒')

# 装饰器
def deco(func):
    def wrapper():
		start = time.time()
    	func()
    	end = time.tiem()
		pirnt(end-start)
	return wrapper

# 定义变量接收返回值
timesleep = deco(timesleep)
timesleep()

4.完善装饰器

  • 上述的装饰器,最后调用timesleep()的时候,其实是在调用wrapper(),因此如果原始的timesleep()有返回值的时候,wrapper()函数的返回值应该和timesleep()的返回值相同,也就是说,我们需要同步原始的timesleep()和wrapper()的返回值
# 源码
import time
def timesleep():
    time.sleep(1)
    print('睡眠一秒')
	return 666

# 装饰器
def deco(func):
    def wrapper():
		start = time.time()
    	res = func()
    	end = time.tiem()
		pirnt(end-start)
        return res
	return wrapper

# 定义变量接收返回值
timesleep = deco(timesleep)
res = timesleep()
print(res)
  • 如果原始的timesleep()函数需要传参,那么我们之前的装饰器是无法实现该功能的,由于有wrapper() = timesleep(),所以给wrapper()函数传参即可
# 源码
import time
def timesleep(*args,**kwargs):
    time.sleep(1)
    print('睡眠一秒')
    print(args,kwargs)
	return 666

# 装饰器
def deco(func):
    def wrapper(*args,**kwargs):
		start = time.time()
    	res = func(*args,**kwargs)
    	end = time.tiem()
		pirnt(end-start)
        return res
	return wrapper

# 定义变量接收返回值
timesleep = deco(timesleep)
res = timesleep(2,3,3,66,name='king',age=20)
print(res)

5.装饰器语法糖

  • 在被装饰函数正上方,并且是单独一行写上@装饰器名
# 源码
import time

# 装饰器
def deco(func):
    def wrapper(*args,**kwargs):
		start = time.time()
    	res = func(*args,**kwargs)
    	end = time.tiem()
		pirnt(end-start)
        return res
	return wrapper

@deco
def timesleep(*args,**kwargs):
    time.sleep(1)
    print('睡眠一秒')
    print(args,kwargs)
	return 666

res = timesleep(2,3,3,66,name='king',age=20)
print(res)

6.装饰器模板

def deco(func):
    def wrapper(*args,**kwargs):
        res = func(*args,**kwargs)
        return res
    return wrapper

二、有参装饰器

1.三层闭包

  • 由于两层的装饰器,参数必须得固定为 func ,但三层的装饰器解除了这个限制,我们不仅可以使用上述单个参数的三层装饰器,多个参数的只需要在三层装饰器中多加入几个参数即可。也即是说,三层装饰器已经够用,在多一层已是多余
is_login_dic = {'username':None}

def auth(origin):
    def login_deco(func):
        def wrapper(*args,**kwargs):
            if origin == 'file':
                if not is_login_dic['username']:
                    username = input('请输入注册用户名:').strip()
                    if username != 'king':
                        print('非法登陆')
                        return
                    is_login_dic['username'] = username
                    res = func(*args,**kwargs)
                    return res
                else:
                    res = func(*args,**kwargs)
                    return res
			elif origin == 'mysql':
                print('非法登陆')
			else:
                print('登陆失败')
		return wrapper
    return login_deco

# f = origin('file')  
# shopping = f(shopping)
# shopping()

@auth('file')
def shopping():
    print('欢迎光临')
    
@auth('mysql')
def withdraw():
    print('欢迎提现')
原文地址:https://www.cnblogs.com/itboy-newking/p/10958983.html