python 函数对象
在介绍装饰器之前,先介绍一下python的函数对象。在python中,万物皆对象,包括函数。函数也是一个对象,在python中,我们可以这样对一个函数进行处理:
def func():
print("--> run func")
def run_func(_func):
print("--> decorate")
_func()
run_func(func)
在python中,可以直接把函数对象当成是参数传入。运行代码,会输出
>> --> decorate
>> --> run func
装饰函数
上面的代码里面,每次都要敲run_func(func)来进行调用,太麻烦了。可以使用闭包函数来让代码更简洁。上面的代码可以等价于:
def func():
print("--> run func")
def decorate(_func):
def _dec(*args, **kwargs):
print("--> decorate")
_func(*args, **kwargs)
return _dec
my_func = decorate(func)
my_func()
decorate函数返回的是一个_dec的函数对象,也就是说my_func指向的是_dec函数。每次执行my_func时,_dec函数里面的逻辑都会被依次从上往下执行。
python装饰器
python给这种装饰函数提供一个语法糖,那就是装饰器。所谓语法糖,就是让代码变得更加简洁、易懂的语法。上面这段代码和上面是一样的效果。
def decorate(_func):
def _dec(*args, **kwargs):
print("--> decorate")
_func(*args, **kwargs)
return _dec
@decorate
def func():
print("--> run func")
func()
其中 @decorate 就是一个装饰器,这个语法相当于帮我们做了下面这个操作。
func = decorate(func)
这样我们每次调用func的时候,其实是真正调用的是装饰器函数返回的函数对象。
那么装饰器有什么用呢?装饰器可以动态地修改函数,比如说我想要统计某些函数的调用时间,可以这样写
import time
def cal_time(func):
def _dec(*args, **kwargs):
start = time.time()
ret = func(*args, **kwargs)
print("call func", func, time.time()-start)
return ret
return _dec
class A:
@cal_time
def func(self):
print("hahaha")
带参数的装饰器
有些时候我们想要让装饰器在不同的情景下有不一样的效果。
比如说我们想要统计调用时间过长的函数,可以这样写:
import time
def cal_time(t):
def f(func):
def _dec(*args, **kwargs):
start = time.time()
ret = func(*args, **kwargs)
cost = time.time() - start
if cost > t:
print("call func", func, cost)
return ret
return _dec
return f
class A:
@cal_time(0.1)
def func(self):
time.sleep(0.2)
print("hahaha")
类装饰器
装饰器不仅是可以作用到函数上,也可以作用到类对象上,来动态地为类添加属性或者修改类方法。
import time
def useful_dec(cls):
func = cls.func # 保存原函数
def _func(self, *args, **kwargs): #
print("sleeping...")
time.sleep(2) # 等两秒,让客户加钱优化
ret = func(self, *args, **kwargs)
return ret
cls.func = _func
return cls
@useful_dec
class A(object):
def func(self):
print("hahaha")