目录
官方定义
装饰器本质上是一个Python函数,它可以让被装饰函数或方法在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。装饰器一般采用语法糖的形式,是一种语法格式。比如:@property,@wraps()。
函数装饰器的使用
实现一个最简单的装饰器
使用装饰器可以将一些通用的功能从函数中抽离出来。
给出一个示例函数
import time
def log():
print('start!')
time.sleep(5)
print('log')
print('end!')
log()
------------------
start!
log
end!
使用装饰器的写法
import time
def sleep(func):
def inner():
print('start!')
time.sleep(5)
func()
print('end!')
return inner
@sleep
# 相当于sleep(log())
def log():
print('log')
log()
------------------
start!
log
end!
多装饰器嵌套
多个装饰器时是依次嵌套执行的
import time
def sleep1(func):
def inner():
print('start!sleep1')
time.sleep(5)
func()
print('end!sleep1')
return inner
def sleep2(func):
def inner():
print('start!sleep2')
time.sleep(5)
func()
print('end!sleep2')
return inner
@sleep1
@sleep2
# 相当于sleep1(sleep2(log()))
def log():
print('log')
log()
------------------
start!sleep1
start!sleep2
log
end!sleep2
end!sleep1
带参数的装饰器
由于装饰器只能接收一个参数,并且还是函数类型。所以如果想向装饰器传递其他参数,正确的写法应该是在装饰器外面再包裹上一个函数,让最外面的函数接收参数,返回的是装饰器,因为@符号后面必须是装饰器实例。
import time
def setTime(second):
def sleep(func):
def inner():
print('start!'second)
time.sleep(second)
func()
print('end!'second)
return inner
return sleep
@setTime(5)
def log():
print('log')
log()
------------------
start!5
log
end!5
装饰器内获取被修改函数的属性
函数传入装饰器后会失去它原先的属性,比如参数。这时就需要用到@wraps装饰器了。
import time
from functools import wraps
def setTime(second):
def sleep(func):
@wraps(func)
def inner(*args, **kwargs):
print('start!', func.__module__, func.__name__, second)
time.sleep(second)
func(*args, **kwargs)
print('end!', func.__module__, func.__name__, second)
return inner
return sleep
@setTime(5)
def log(msg):
print(msg)
log('log')
------------------
start! __main__ log 5
log
end! __main__ log 5
类装饰器的使用
类装饰器这个写法,主要思路就是返回一个增加了新功能的函数对象,只不过这个函数对象是一个类的实例对象。由于装饰器是可调用对象,所以必须在类里面实现__call__方法,这样由类生成的各种实例加上()就可以运行了。因为与函数装饰器是类似的,所以这里只展示一个最复杂的用法,装饰器带参数,且被装饰函数也带参数。
import time
from functools import wraps
class Decorator:
def __init__(self, second):
self.second = second
def __call__(self, func,*args, **kwargs):
@wraps(func)
def inner(*args, **kwargs):
print('start!', func.__module__, func.__name__, self.second)
time.sleep(self.second)
func(*args, **kwargs)
print('end!', func.__module__, func.__name__, self.second)
return inner
@Decorator(5)
def log(msg):
print(msg)
log('log')
------------------
start! __main__ log 5
log
end! __main__ log 5
参考资料
python中带有参数的装饰器_python 带参数的装饰器_IT之一小佬的博客-CSDN博客
python装饰器——获取被修饰的函数参数_python 装饰器获取被装饰函数属性_松子吃松子的博客-CSDN博客