07 装饰器 (wrapper)

装饰器的形成过程:

从最简单的,到有返回值的,到有一个参数的,再到万能参数。

装饰器的作用

不想修改函数的调用方式,但还想在原来的基础上添加功能,下面的timer就是一个装饰器,只是对一个函数有一些装饰的功能。

def func():
    time.sleep(0.01)
    print('你好!')

def timmer(f):  # 装饰器函数
    def inner():
        start = time.time()
        ret = f()  # 被装饰的函数
        end = time.time()
        print(end - start)
        return ret

    return inner

func = timmer(func)
func()

注意!!!
上面代码中inner函数中,return inner一定不能再后面加括号。因为在被调用时,inner返回的是内存地址,func = timmer(func)执行时,func得到的也是inner函数的内存地址,最后func()执行时,实际上执行的时timmer函数中的inner函数。

语法糖
import time

def timmer(f):  # 装饰器函数
    def inner():
        start = time.time()
        ret = f()  # 被装饰的函数
        end = time.time()
        print(end - start)
        return ret

    return inner

@timmer  # 语法糖
def func():
    time.sleep(0.01)
    print('你好!')

# func = timmer(func)
func()  # inner()

此时,相较于上个代码,加上了语法糖的修饰字符@timmer,这个时候,就可以把func = timmer(func)这句话省略不写。同时,在装饰函数中,要写返回值,即上面代码中的return ret。但是要注意的是,修饰函数要写在被修饰函数的前面。请仔细对比上面两个代码的区别!!!
最后,func()实际上运行的是inner函数。

原则

  1. 开放:对扩展是开放的
  2. 封闭:对修改是封闭的

装饰带参数函数的装饰器

import time

def timmer(f):  # 装饰器函数
    def inner(*args, **kwargs):
        # (1,2) /(1)
        start = time.time()
        ret = f(*args, **kwargs)  # f(1,2)       #被装饰的函数
        end = time.time()
        print(end - start)
        return ret

    return inner

@timmer  # 语法糖 @装饰器函数名
def func(a, b):  # 传两个参数的被装饰的函数
    time.sleep(0.01)
    print('你好!!', a, b)
    return '新年好1'

# @timmer  # 语法糖 @装饰器函数名
# def func1(a):     #只创一个参数的被装饰的函数
#     time.sleep(0.01)
#     print('大家好',a)
#     return '新年好'
# func = timmer(func)

ret = func(1, 2)  # inner()
ret1 = func(1, b=6)  # inner()
print(ret)
print(ret1)

输出:
在这里插入图片描述
装饰器函数中使用*args,**kwargs可以传入任意多个参数。

装饰器的固定模式(可能是笔试题)

def wrapper(f):
    def inner(*args, **kwargs):
        # 在装饰函数前要做的事
        ret = f(*args, **kwargs)
        # 在装饰函数之后要做的事
        return ret

    return inner

@wrapper  # qqxing = wrapper(qqxing)
def qqxing():
    print(123)

ret = qqxing()  # inner
多个装饰器装饰同一个函数

有些时候,我们也会用到多个装饰器装饰同一个函数的情况。

import functools  # from functools import wraps

def wrapper1(f):
    @functools.wraps(f)  # import functools是导入functools模块。现在,只需记住在定义wrapper()的前面加上@functools.wraps(func)即可。
    def inner1():
        print('wrapper1 ,before func')
        ret1 = f() + '1111111111'
        print('wrapper1 ,after func')
        return ret1

    return inner1

def wrapper2(func):
    @functools.wraps(func)
    def inner2():
        print('wrapper2 ,before func')
        ret2 = func() + '2222222222'
        print('wrapper2 ,after func')
        return ret2

    return inner2

@wrapper1
@wrapper2
def f():
    return 'in f'

ret = f()
print(ret)
print(f.__name__)  # 如果前面没有@function.wraps(),就会出现inner1

输出:
在这里插入图片描述
因为我们讲了函数也是对象,它有__name__等属性,但你去看经过装饰器之后的函数,它们的__name__已经从原来的’f’变成了’inner’,所以我们要在装饰器最内层函数前加上@functools.wraps(func)或者引用from functools import wraps,然后又在修饰器前面加上@wraps(func)就可以保持名字不变。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值