Python高级特性之装饰器

装饰器:定义一个装饰函数,函数必须返回一个闭包(闭包就是执行时所需要的外部变量+函数对象,关于闭包的具体介绍,可参考https://blog.csdn.net/DansonC/article/details/94824808)函数,并且被装饰的函数会被python自动传递给装饰函数,作为装饰函数的一个参数。

装饰器的具体定义:
1、把要装饰的方法作为输入参数;
2、在函数体内可以进行任意的操作(可以想象其中会有很多应用场景);
3、只要确保最后返回一个可执行的函数即可(可以是原来的输入参数函数,也可以是一个新函数)。

装饰器的分类
装饰器分为无参数decorator和有参数decorator
无参数decorator:生成一个新的装饰器函数
有参数decorator:装饰函数先处理参数,再生成一个新的装饰器函数,然后对函数进行装饰。

使用装饰器,需要在其他函数的上面写个@xxxxx,如下面例子的@timer

举个例子,使用装饰器来计算执行一个函数的耗时:

import time
def timer(func):  #装饰函数
    def wrapper(*arg,**kw):
        time1=time.time()#被装饰函数调用前做的事情
        print("******before******")
        func(*arg,**kw)  #做一次函数调用
        time2=time.time()#被装饰函数调用后做的事情
        print("******after******")
        print("time elapsed:%s" %(time2-time1))  #计算执行被装饰函数的耗时
    return wrapper
    #闭包:func(闭包变量)+wrapper(函数)

@timer
def a(count):  #被装饰函数
    print("执行次数:",count)
    i =1
    while i<count:
        i+=1
    print("a is over!")

a(100)

在这里插入图片描述
装饰器其实就是一个闭包,把一个函数当做参数后返回一个替代版函数。
装饰函数中的闭包函数结构如下:

def wrapper(*arg,**kw):
    xxx   干一些事情
    func(*arg,**kw)  #执行被装饰函数
    yyy   干另外一些事情

最后装饰函数返回这个闭包,return wrapper,这样就是一个完整的装饰器

装饰器的规则:
规则1:
函数func上面定义了@xxxx,那么等价于 func = xxxx(func)
规则2:
装饰函数xxxx,必须返回一个闭包(一个内置函数+func)

下面来具体分析一下装饰器整个执行过程

def deco(func):
    def _deco():
        print ("before myfunc() called.")
        func()
        print ("  after myfunc() called.")
        # 不需要返回func,实际上应返回原函数的返回值
    return _deco

@deco   #myfunc=deco(myfunc)
def myfunc():
    print (" myfunc() called.")
    return 'ok'

#myfunc=deco(myfunc)—>返回了一个闭包:_deco+myfunc

myfunc() #---->执行闭包函数_deco()
myfunc() #---->执行闭包函数_deco()

执行逻辑:
deco(myfunc)
print (“before myfunc() called.”)
myfunc()
print (" after myfunc() called.")
print (" myfunc() called.")
print (" myfunc() called.")

执行过程解释:
装饰函数deco
被装饰函数myfunc
@deco
def myfunc(): —>myfunc= deco(myfunc)
myfunc = deco(myfunc)干了什么呢?
1 调用了deco(myfunc)
2 返回闭包:_deco+外包变量myfunc
3 闭包赋值给了myfunc
4 提醒myfunc变为了闭包函数对象

myfunc()—>干了什么呢?
1 _deco()执行了
2 print (“before myfunc() called.”)
3 myfunc()
4 print (" after myfunc() called.")

myfunc()—>干了什么呢?
1 _deco()执行了
2 print (“before myfunc() called.”)
3 myfunc()
4 print (" after myfunc() called.")

执行结果:
before myfunc() called.
myfunc() called.
after myfunc() called.
before myfunc() called.
myfunc() called.
after myfunc() called.
在这里插入图片描述

被装饰函数带参数

def deco(func):
    def _deco(*arg,**kw):
        print ("before %s called." %func.__name__)
        print(func(*arg,**kw))
        print ("  after %s called." %func.__name__)
        # 不需要返回func,实际上应返回原函数的返回值
    return _deco
#闭包:_deco+func

@deco   
def myfunc(a,b):
    print (" myfunc() called.")
    return a+b


myfunc(1,2)
myfunc(3,4)

在这里插入图片描述

装饰器带参数

def deco(s):
    def __deco(func):
        def _deco(*arg,**kw):
            print ("before %s called." %func.__name__,s)
            print(func(*arg,**kw))
            print ("  after %s called." %func.__name__,s)
            # 不需要返回func,实际上应返回原函数的返回值
        return _deco
    return __deco
#闭包:_deco+func

@deco("hello")   
def myfunc(a,b):
    print (" myfunc() called.")
    return a+b


myfunc(1,2)
myfunc(3,4)

1)多了一步:deco(“hello”) —>返回了闭包:__deco+s
deco=闭包:__deco+s
2)@deco—>__deco(func)+s—>返回了一个闭包_deco+func+s
后面的过程跟上一步的过程一样。

在这里插入图片描述
内置装饰器
Python中内置的装饰器有三个:
staticmethod:定义实例方法为静态方法
classmethod:定义实例方法为类方法
property:对类属性的操作

一个函数可以同时被多个装饰器进行装饰,
同时对一个函数使用多个不同的装饰器进行装饰时,装饰器的顺序是怎样的呢?

@A
@B
@C
def f():
    pass

等价于:
f = A(B(C(f)))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值