装饰器
1.定义
装饰器函数本质是闭包(外部函数的返回值是内部函数的引用),为了运行时动态的增加功能,又不想改动原函数本身的代码和函数的调用方式
2.装饰器的原理
- 功能函数foo,实现某个功能
def foo():
print("This is func foo, doing somethings……")
- 现在需要在不改变foo函数原有函数的代码和调用方式的情况下新增功能1,可以使用如下方式实现:
def decorator(func):
def inner():
func()
print("This is add func, doing somethings else。。。。。")
return inner
def foo():
print("This is func foo, doing somethings……")
foo = decorator(foo)
if __name__ == '__main__':
foo()
- 以上实现方式的foo = decorator(foo)可以在原函数前加上@装饰器函数名实现,即@decorator
def decorator(func):
def inner():
func()
print("This is add func, doing somethings else。。。。。")
return inner
@decorator
def foo():
print("This is func foo, doing somethings……")
if __name__ == '__main__':
foo()
3.原函数带参数的装饰器实现
目标函数带有参数时,装饰器可以使用不定长参数来传递参数
def decorator(func):
def inner(*args, **kwargs):
func(*args, **kwargs)
print("This is add func, doing somethings else。。。。。")
return inner
@decorator
def foo(name):
print("This is func foo, doing somethings and name is %s……" % name)
if __name__ == '__main__':
foo('foo')
4.根据装饰器带有的参数不同执行不同的结果
有打印日志的和记录函数运行时间的装饰器函数,不传递参数默认不打印日至,传递不为False的参数来打印日志
import time
def decorator(log=0):
def wrapper(func):
def inner(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
time.sleep(1)
end_time = time.time()
runtime = end_time - start_time
print("runtime is %.4fs。。。。。" % runtime)
if log:
print("Logging now ………………")
return inner
return wrapper
@decorator(1)
def foo(name):
print("This is func foo, doing somethings and name is %s……" % name)
if __name__ == '__main__':
foo('foo')
5.装饰器被调用的时间点
运行下面代码
def decorator(func):
print("calling decorator……")
def inner():
func()
print("This is add func, doing somethings else。。。。。")
return inner
@decorator
def foo():
print("This is func foo, doing somethings……")
运行上面代码发现打印了:calling decorator……
明装饰器外部函数在加载内存(或者导包)的第一时间就运行了,原因是@decorator等价于foo = decorator(foo),此处decorator被调用了
6.被装饰过的函数的函数名
运行下面代码
def decorator(func):
def inner():
func()
print("This is add func, doing somethings else。。。。。")
return inner
@decorator
def foo():
print("This is func foo, doing somethings……")
if __name__ == '__main__':
foo()
print("The func foo's name is ", foo.__name__)
运行结果为:
This is func foo, doing somethings……
This is add func, doing somethings else。。。。。
The func foo's name is inner
发现被装饰器装饰后foo函数的名称变为了inner
解决办法
- 方法一:手动修改函数名称
def decorator(func):
def inner():
func()
print("This is add func, doing somethings else。。。。。")
inner.__name__ = func.__name__
return inner
@decorator
def foo():
print("This is func foo, doing somethings……")
if __name__ == '__main__':
foo()
print("The func foo's name is ", foo.__name__)
运行结果:
This is func foo, doing somethings……
This is add func, doing somethings else。。。。。
The func foo's name is foo
- 方法二:给inner函数加上functools模块的wraps装饰器函数,将原函数作为形参传入。
import functools
def decorator(func):
@functools.wraps(func)
def inner():
func()
print("This is add func, doing somethings else。。。。。")
return inner
@decorator
def foo():
print("This is func foo, doing somethings……")
if __name__ == '__main__':
foo()
print("The func foo's name is ", foo.__name__)
运行结果:
This is func foo, doing somethings……
This is add func, doing somethings else。。。。。
The func foo's name is foo
7.多个装饰器装饰同一个函数
import functools
def decorator2(func):
print("decorator2")
@functools.wraps(func)
def inner():
func()
print("This is add func2, doing somethings else。。。。。")
return inner
def decorator1(func):
print("decorator1")
@functools.wraps(func)
def inner():
func()
print("This is add func1, doing somethings else。。。。。")
return inner
@decorator2
@decorator1
def foo():
print("This is func foo, doing somethings……")
if __name__ == '__main__':
foo()
print("The func foo's name is ", foo.__name__)
运行结果:
decorator1
decorator2
This is func foo, doing somethings……
This is add func1, doing somethings else。。。。。
This is add func2, doing somethings else。。。。。
The func foo's name is foo
先装饰的先执行,后装饰的后执行
@decorator2
@decorator1
等价于
foo = decorator2(decorator1(foo))
8.类装饰器
class DecoratorClass(object):
def __call__(self, *args, **kwargs):
return self.call_func
def call_func(self):
print("This is add func from class decorator……")
@DecoratorClass()
def foo():
print("This is func foo, doing somethings……")
if __name__ == '__main__':
foo()
运行结果:
This is add func from class decorator……
@DecoratorClass() 等价于 foo = DecoratorClass()(foo)
定于装饰器类时,重写对象的__call__方法,返回一个功能函数的引用即可。