python 装饰器《一》基础装饰器、参数装饰器、类装饰器、装饰器执行顺序、functools.wraps功能与作用

一、定义与应用场景
  • 装饰器在不修改被装饰对象的原代码以及调用方式的前提下为被装饰对象添加新功能的可调用对象

  • 即:给现有的模块加上一些小功能(小功能可能好多模块都会用到), 但又不让这个功能侵入到原有的代码里去

  • 说人话 在不修改原函数的代码的情况下,添加新的功能调用函数的函数,传入的是一个函数,返回的也是一个函数

    添加的位置: 可以在执行原函数之前加,也可也在执行原函数之后添加

  • 装饰器的功能

    引入日志函数执行时间统计
    执行函数前预备处理执行函数后清理功能
    权限校验缓存
    def decorate_func(func):        # 传入寒暑
       def wrapper():
           return 100
       return wrapper     # 返回函数名
    
    @decorate_func
    def hello():
        return 200
    
    func2 = decorate_func(hello)
    print(hello()) 100
    
    decorate_func(func) 返回了 wrapper() 函数,
    所以,hello 其实变成了 wrapper 的一个变量,
    而后面的 hello() 执行其实变成了 wrapper()
    

    把一个函数当参数传到另一个函数中,然后再回调, 把 decorator 这个函数的返回值赋值回了原来的 func

二、简单示例与调用过程
  1. 装饰器只能在调用原函数之前 或者之后 添加功能,而不能在函数的中间添加功能

  2. 只要用装饰器装饰了的函数,那么不管被调用多少次,都是装饰之后的效果

  3. 紧挨着的装饰器先执行,执行完成,交给外部的装饰器装饰

    import time
    def decorator_time(func):
        def wrapper(*args, **kvargs):
            start_time = time.time()  # ----->函数运行前时间
            func(*args, **kvargs)
            end_time = time.time()    # ----->函数运行后时间
            cost_time = end_time - start_time  # ---->运行函数消耗时间
            print("%s消耗时间为%s" % (func.__name__, cost_time))
            return cost_time
        return wrapper  # ---->装饰器其实是对闭包的一个应用
    
    def check_auth(func):
        def wrapper(*args, **kwargs):
            print("这是新添加的 权限校验功能")
            ret = func(*args, **kwargs)
            return ret
        return wrapper
    
    def parame_log(func):
        def wrapper(*args, **kwargs):
            print("这是新添加的 用户提交参数日志功能")
            ret = func(*args, **kwargs)
            return ret
        return wrapper
    
    @check_auth        #添加权限的装饰器
    @parame_log        #添加log日志的装饰器
    @decorator_time    #装饰器名称就是上面函数名称
    def my_function():
        return 'Hello world!'
    
    if __name__ == '__main__':
        t = my_function()
        print(t)
    

    简单解释一下

    1. 装饰器decorator_time 本身是一个函数,要装饰什么函数?
    2. 一看, 原来要装饰my_function函数, 于是将my_function函数当做参数传入到decorator_time函数中
    3. decorator_time内部又定义了一个函数wrapper,等一下, wrapper这个函数有毛用?wrapper接受的参数又是是的参数?
    4. 哦偶!原来wrapper函数才是真正对my_function函数起装饰作用的。wrapper接受参数是my_function的参数不变
    5. decorator_time怎么与两个返回值?
      内部函数wrapper返回的my_function返回值,将其返回到外部函数中 decorator_time
      外部 decorator_time函数返回值,就返回啦
三、参数化装饰器

就是在上述的装饰情况下,再次添加一层函数,可用来传递参数

def tags(tag):
    def set_decorate(func):
        def wrapper(*args, **kwargs):
            res = func(*args, **kwargs)
            res = res + tag
            return res
        return wrapper
    return set_decorate


@tags('1024')  可传参数
def my_function():
    return 'Hello world!'

if __name__ == '__main__':
    t = my_function()
    print(t)
四、functools.wraps() 功能与作用

被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变)
加上functools的wrap,它能保留原有函数的名称和函数属性
functools.wraps以保留被装饰函数的元数据

import time
import functools

def decorator(func):
	@functools.wraps(func)
    def wrapper(*args, **kvargs):
        start_time = time.time()  
        func(*args, **kvargs)
        end_time = time.time()  
        cost_time = end_time - start_time 
        print("%s消耗时间为%s" % (func.__name__, cost_time))
        return cost_time
    return wrapper 
    
@my_decorator
def my_function(arg1, arg2):
    print(f"Inside the function with arg1: {arg1} and arg2: {arg2}")

my_function(10, 20)
print("Function name:", my_function.__name__)
print("Function docstring:", my_function.__doc__)
在这个修改后的示例中,我们去掉了@functools.wraps(func)这一行
当我们调用my_function(10, 20)并打印函数名和文档字符串时
我们可以看到函数名变成了wrapper,而文档字符串变成了None,这说明元数据丢失了
五、类装饰器
  1. 初始化方法时保存传递函数的本身,
  2. 在call 方法中执行 保存的函数。执行之前、或之后可进行额外的操作
    call将一个类的实例可以像函数调用
    import time
    
    class Timer:
    
        def __init__(self, func):
            self.func = func
    
        def __call__(self, *args, **kwargs):
            start = time.time()
            ret = self.func(*args, **kwargs)
            print(f"花费时间: {time.time() - start}")
            return ret
    
    @Timer
    def login(username, password):
        print(f"login:  username: {username}, password: {password}")
    login('zhangsan', '123456')
    
    # 上面装饰器代码等价于下面
    def login2(username, password):
        print(f"login2:  username: {username}, password: {password}")
    
    userlogin = Timer(login2)
    userlogin('zhangsan', '123456')
    
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风华浪浪

讨个老婆本呗

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值