python中的装饰器

十一、装饰器

1、装饰器函数的本质:一个闭包函数
2、装饰器函数的作用:
在不修改原函数及其调用方式的情况下对原函数功能进行扩展
3、语法糖
格式:@装饰器名称

举例1:创建一个计算函数计算时间的闭包函数

import time


def func():
    print('11111')


def outter(fun):
    def inner():
        start = time.time()
        fun()
        end = time.time()
        print(end - start)

    return inner


f = outter(func) #如果只进行到这一步,则不会有任何显示
f()
'''
输出如下:
11111
0.0
'''

举例2:使用语法糖修改装饰器

语法糖:@装饰器名称,等价于func=outter(func),所以调用时,只需要是func()就可以调用

def outter(fun):
    def inner():
        start = time.time()
        fun()
        end = time.time()
        print(end - start)

    return inner

@outter
def func():
    print('11111')


func()

如上代码所示,最后func()调用时,并不是调用上面的func()函数,@outter等价于func=outter(func),所以最后func()执行时,执行的是outter(func)
举例3:创建一个带返回值的装饰器

def outter(fun):
    def inner():
        start = time.time()
        ret = fun()
        end = time.time()
        print(end - start)
        return ret

    return inner


@outter
def func():
    print('11111')
    return 'hhh'


a=func()
print(a)
'''
输出如下:
11111
0.0
hhh
'''

在func()函数中设置返回值,然后在inner()函数中设置变量ret用来接收func()函数的返回值,然后在inner()函数中返回ret。最后调用这个装饰器时,用一个变量接收,然后输出这个变量
举例4:创建一个带参数的装饰器

def outter(fun):
    def inner(a):
        start = time.time()
        fun(a)
        end = time.time()
        print(end - start)

    return inner


@outter
def func(s):
    print(s)


func('lee')
'''
输出如下:
lee
0.0
'''

如上代码所示,func()函数中的s,及其函数中print()中的s,和装饰器中inner()函数中的a,及其函数内的fun()函数中的a,都是形参,在最后调用func(‘lee’)的时候,不管是a还是s都表示为lee。

举例5:定义一个可以传递任意参数的装饰器

def outter(fun):
    def inner(*args, **kwargs):
        start = time.time()
        fun(*args, **kwargs)
        end = time.time()
        print(end - start)

    return inner


@outter
def func(*args, **kwargs):
    print(args, kwargs)


func('lee', 21, height=1.78)
'''
输出如下:
('lee', 21) {'height': 1.78}
0.0
'''

如上代码如示,使用*args和**kwargs可以接收任何参数

使用@wraps(func) 解决被装饰函数的信息不能查看问题

from functools import wraps


def outter(fun):
    @wraps(fun)
    def inner(*args, **kwargs):
        start = time.time()
        fun(*args, **kwargs)
        end = time.time()
        print(end - start)

    return inner


@outter
def func(*args, **kwargs):
    '''

    :param args: 使参数变成一个元组,所有传递的参数变成元组的元素
    :param kwargs: 使参数变成一个字典,所有传递的参数变成字典的键值对
    :return:
    '''
    print(args, kwargs)


func('lee', 21, height=1.78)
print(func.__doc__)
print(func.__name__)

输出为:

('lee', 21) {'height': 1.78}
0.0


    :param args: 使参数变成一个元组,所有传递的参数变成元组的元素
    :param kwargs: 使参数变成一个字典,所有传递的参数变成字典的键值对
    :return:
    
func

给函数添加多个装饰器

def test1(fun):
    def inner1():
        print('start------test1')
        fun()
        print('end------test1')

    return inner1


def test2(fun):
    def inner2():
        print('start------test2')
        fun()
        print('end------test2')

    return inner2


@test1 # inner1=test1(inner2)
@test2
def func():
    print('this is func()')


func()

输出为:

start------test1
start------test2
this is func()
end------test2
end------test1

以前我们学习的程序运行的过程都是从上往下,但是这里的装饰器并不是这样。
它是先运行与被装饰的函数距离更近的装饰器,所以是先运行test2的,此时test2(fun)运行时,其中的fun参数代入的是我们被修饰的函数func(),然后return inner2(),与此同时,计算机把inner2返回给test1(fun)作为参数fun。

所以运行的顺序是,先调动test2(fun),并把func()函数作为fun参数,然后return inner2,这个时候计算机发现test1需要一个参数,就把inner2作为test1(fun)中的fun代入了,然后运行的是test1(inner2)
第一步:test1(inner2)开始运行,输出start------test1。
第二步:然后继续运行,到了fun()这时,此时的fun其实是inner2。所以调动了inner2,输出了start------test2。
第三步:然后到了下一步,就是inner2中的fun()这一步,此时的fun是函数func(),所以输出了this is func().
第四步:然后进行运行,输出了end------test2,与此同时,inner2函数结束了,所以就返回了test1中的inner1函数。
第五步:程序继续运行,输出了end------test1

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值