文章目录
- 1. 装饰器的定义与原型
- 2. 装饰器应用场景 - 统计函数执行时间
- 3. 装饰器语法
- 3.1. 装饰器嵌套
- 3.2. 装饰带有参数的函数
- 3.3. 带有参数的装饰器
- 3.4. 类装饰器装饰函数
- 3.5. 用类方法装饰函数
- 3.6. 函数装饰器装饰类
- 3.7. 类装饰器装饰类
1. 装饰器的定义与原型
- 装饰器定义
在不改变原有函数代码,且保持原函数调用方法不变的情况下,给原函数增加新的功能(或者给类添加属性和方法)
- 核心思想
用一个函数(或者类)去装饰一个旧函数(或者类),造成一个新函数(或新类) - 语法规则
在原有的函数上加上@,装饰器会把下面的函数当作参数转递到装饰器中,@又被称为语法糖 - 应用场景
引入日志,函数执行时间的统计,执行函数前的准备工作,执行函数后的处理工作,权限校验,缓存等
- 装饰器的原型
利用闭包,把函数当作参数传递,并在函数内去调用传递进来的函数,并返回一个函数
def outer(func):
def inner():
# 功能1
func()
# 功能2
return inner
def old():
# 旧函数功能
old = outer(old) # 返回inner函数赋给old
old() # 相当于inner()
# 执行结果
1. 功能1
2. 旧函数功能
3. 功能2
def outer(func):
def inner():
# 功能1
func()
# 功能2
return inner
@outer # 此处相当于old = outer(old)
def old():
# 旧函数功能
2. 装饰器应用场景 - 统计函数执行时间
import time
def runtime(func):
def inner():
start = time.perf_counter()
func()
end = time.perf_counter()
print(f'函数的执行时间为:{end - start:0.2f}')
return inner
@runtime
def func():
for i in range(10):
print(i)
time.sleep(1)
func()
3. 装饰器语法
3.1. 装饰器嵌套
- 先使用离得近的装饰器,在装饰完的基础上,继续新的装饰
import time
def runtime(func):
def inner():
start = time.perf_counter()
func()
end = time.perf_counter()
print(f'函数的执行时间为:{end - start:0.2f}')
return inner
def log(func):
def inner():
print(time.gmtime(time.time()).tm_sec)
func()
print(time.gmtime(time.time()).tm_sec)
return inner
@log
@runtime # 相当于func = log(func = runtime(func))
def func():
for i in range(10):
time.sleep(1)
func()
'''
执行结果
执行前的秒数
函数的执行时间
执行后的秒数
'''
3.2. 装饰带有参数的函数
import time
def runtime(func):
def inner(name):
start = time.perf_counter()
func(name)
end = time.perf_counter()
print(f'函数的执行时间为:{end - start:0.2f}')
return inner
@runtime
def func(name):
print(name)
func('Jack')
3.3. 带有参数的装饰器
import time
def choose(opt):
def runtime(func):
def inner1(name):
start = time.perf_counter()
func(name)
end = time.perf_counter()
print(f'函数的执行时间为:{end - start:0.2f}')
def inner2(name):
print('Hello')
func(name)
if opt == 1:
return inner1
else:
return inner2
return runtime
@choose(2)
def func(name):
print(name)
func('Jack')
3.4. 类装饰器装饰函数
- 此时的func函数是属于类Outer的inner方法
class Outer():
# 当把该类当作函数调用时,obj()自动触发__call__
def __call__(self, func):
self.func = func
return self.inner
def inner(self):
print(1)
self.func()
print(2)
@Outer()
def func():
print('Hello')
func()
3.5. 用类方法装饰函数
class Test():
def outer(self,func):
self.func = func
return self.inner
def inner(self):
print(1)
self.func()
print(2)
@Test.outer
def func():
print('Hello')
func()
3.6. 函数装饰器装饰类
def Outer(_class):
def newfunc():
print('新方法')
_class.newfunc = newfunc
_class.newattrib = '新属性'
return _class
@Outer
class Test():
def outer(self,func):
self.func = func
return self.inner
def inner(self):
print(1)
self.func()
print(2)
Test.newfunc()
print(Test.newattrib)
3.7. 类装饰器装饰类
class Outer():
def __init__(self) -> None:
self.name = '新属性'
def __call__(self, _class):
_class.newfunc = self.newfunc
_class.newattrib = self.name
return _class
def newfunc(self):
print('新方法')
@Outer()
class Test():
def outer(self,func):
self.func = func
return self.inner
def inner(self):
print(1)
self.func()
print(2)
Test.newfunc()
print(Test.newattrib)