装饰器

装饰器

一、无参装饰器

1.1 什么是装饰器?

装饰器,器指的是工具,二而程序中的函数就是具备某一功能的工具,所以装饰器指的是为被装饰器对象(函数)添加额外功能。因此定义装饰器就是定义一个函数,只不过该函数的功能是用来为其他函数添加额外的功能

装饰器本质就是一个函数A,装饰的对象也是一个函数B,用一个函数A去装饰一个函数B,

需要注意的是:

  • 装饰器本身其实就是可以任意调用的对象

  • 被装饰的对象也可以是任意可调用的对象

    def A():
         """装饰器"""
         pass
    
    def B():
         """被装饰的对象"""
        pass
    
    B()
    

1.2 为什么要用装饰器?

如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方法的使用方法,这个时候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能指的是开放的。

装饰器的实现必须遵循两大原则:

  1. 不修改被装饰对象的源代码
  2. 不修改被装饰对象的调用方式

装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。

1.3 如何使用装饰器

def index():
     """被装饰的函数"""
    print('hello, index')
    
index()

对上面函数实现:

1.打印函数运行的时间

1.1 改变了函数体代码,没改变调用方式

import time
def index():
    start = time.time()
    print("hello, index")
    time.sleep(1)
    end = time.time()
    print(end - start)
index()

1.2 没改变调用方式,也没改变源码,但是不通用

import time
def index():
    print("hello, index")
    
start = time.time()
index()
time.sleep(1)
end = time.time()

print(end - start)

2.装饰器

检测index的运行的时间,但是不能改变index的调用方式,以及index的源码

def deco(func): # func = 真正的index
    """装饰器函数"""
    
    def inner():
        start = time.time()
        func() # 真正的index()
        time.sleep(1)
        end = time.time()
        print(ent - start)
    return inner

def index():
    """被装饰的函数"""
    print("hello, index")
    
 # 实现index函数调用   
index = deco(index) # index = inner
index() # f1()

二、装饰器语法糖

在被装饰函数正上方,并且是单独一行写上@装饰器名

def deco(func): # func = 真正的index
    """装饰器函数"""
    
    def inner():
        start = time.time()
        func() # 真正的index()
        time.sleep(1)
        end = time.time()
        print(ent - start)
    return inner

def index():
    """被装饰的函数"""
    print("hello, index")
@deco
index() 

三、装饰器模板

def outter(func):
    def inner(*args, **kwagrs): 
        """
        args: 被装饰的位置形参
        kwargs: 被装饰的默认形参/关键字实参
        """
        res = func(*args, **kwagrs)
        return res
    return inner

def deco(func):
    """装饰器"""
    def inner(*args, **kwargs): # inner是未来要运行的函数
        res = func(*args, **kwargs) # func实际调用的函数
        return res
    return inner

@deco
def index(x, a=12):
    """被装饰的对象"""
    
    print('x:',x,)
    print("a:", a)
    print('hello index')
    
    return index


res = index()
print(res)

实现一个用户登录装饰器。

def login(func):
    def ingfunc(*args, **kwargs):

        username = input("请输入用户名:")
        userpwd = input("请输入密码:")

        if username == 'randy' and userpwd:
            print("登录成功")

            res = func(*args, **kwargs)
        else:
            print('失败')

        return res

    return ingfunc
@time_count
@login  # 多个装饰器从下到上执行
def shopping():
    print('shoppoing')


shopping()

四、三层装饰器(有参装饰器)

# 三层装饰器
def sanceng(engine):
    def outter(func):
        def wrapper(*args, **kwargs):
            # 加功能
            print(engine)
            res = func(*args, **kwargs) # func被装的函数
            return res
        return wrapper
    return outter

@sanceng('file')
def shopping()
	print("shopping")
# 判断账号密码来自于哪个地方
#三层装饰器: 给双层装饰器加参数
def auth(engine):
    def login(func):
        def inner(*args, **kwargs):
            # 登录功能
            if engine == 'file':
                username = input('usrename:')
                pwd = input('pwd:')
                if username == 'nick' and pwd == '123':
                    print('登录成功')
                    res = func(*args, **kwargs)  # shopping()                    return res
                else:
                    print('登录失败')
           elif engine == 'db':
                print('账号密码来自于数据库,非法请求')
        return inner
    return login

@auth('db')
def shopping():
    print('shopping')


login = auth('db')  # login = login
shopping = login(shopping)  # shopping = inner
shopping() # inner()
# 叠加多个装饰器
# 1. 加载顺序(outter函数的调用顺序):自下而上
# 2. 执行顺序(wrapper函数的执行顺序):自上而下

五、三层装饰器模板

def wrapper(param=None):
    def outter(func):
        def innter(*args, **kwargs):
            print(param)
            res = func(*args, **kwargs)
            return res

        return innter

    return outter

六、总结

  1. 装饰作用:为被装饰器装饰的对象添加额外功能,好处在于,不改变被装饰器对象的源代码和调用方式;
  2. 两层装饰器模板
from functools import wraps

def outter(func):
    @wraps(func)
    def innter(*args, **kwargs):
        res = func(*args, **kwargs)
        return res
    return innter
  1. 三层装饰器模板

def wrapper(param=None):

    def outter(func):
        def innter(*args, **kwargs):
            res = func(*args, **kwargs)
            return res
        
        return innter
    
    return outter
在当下的阶段,必将由程序员来主导,甚至比以往更甚。
原文地址:https://www.cnblogs.com/randysun/p/11341112.html