下面将依次介绍装饰器是如何来的,装饰器如何装饰带返回值的函数,如何装饰带参数的函数,多个装饰器如何装饰同一个函数以及什么叫做带参数装饰器。
'''
假设我们想要对于我们写的函数进行计时(这个函数可以很多很多个),那么我们如何做呢?下面是一种方法
'''
import time
def timmer(function): # 这就是装饰器函数
def inner():
start = time.time()
function() # 这就是被装饰的函数
end = time.time()
print(end - start)
return inner # 注意这里是返回内部函数名,不带括号
def func(): #
print("Hello Python")
func = timmer(func)
func() # 注意这里的func()执行的其实是inner函数
# 通过上面这种方法,我们没有修改函数的调用方式,去在原有函数的基础上添加了一些功能,这就是装饰器的一种粗略的模型。
'''
装饰器原则:开放封闭原则
封闭:对修改是封闭的(相当于禁止在函数修改任何东西,即使是添加一个变量名)
开放:对扩展是开放的
装饰器的作用:不想修改函数的调用方式,但是还想在原来的函数前后添加功能
'''
# 在上面的方法中,我们的func函数并没有返回值,但是通常来说,函数都是有返回值的,上面的方法并不能让我们获得func()函数的返回值
def timmer(function): # 这就是装饰器函数
def inner():
start = time.time()
function() # 这就是被装饰的函数
end = time.time()
print(end - start)
return inner # 注意这里是返回内部函数名,不带括号
@timmer # python中的语法糖 @装饰器函数名 这里@timmer就相当于执行了 func = timmer(func) @下面紧跟着的就是被装饰函数
def func(): #
print("Hello Python")
return '你好,世界'
# func = timmer(func)
a = func() # 注意这里的func()执行的其实是inner函数
print(a)
#-----------------------------------------------------------------------------------------------------------
# 那么如何得到func函数的返回值呢?其实只要在inner函数里添加一个接收func函数返回值的变量,并将该变量返回即可
def timmer(function): # 这就是装饰器函数
def inner():
start = time.time()
ret = function() # 这就是被装饰的函数
end = time.time()
print(end - start)
return ret
return inner # 注意这里是返回内部函数名,不带括号
@timmer # python中的语法糖 @装饰器函数名 这里@timmer就相当于执行了 func = timmer(func) @下面紧跟着的就是被装饰函数
def func(): #
print("Hello Python")
return '你好,世界'
a = func() # 注意这里的func()执行的其实是inner函数
print(a)
# 上面就是装饰带返回值函数的装饰器
#-----------------------------------------------------------------------------------------------------------
# 下面是装饰带参数函数的装饰器
def timmer(function): # 这就是装饰器函数
def inner(a):
start = time.time()
ret = function(a) # 这就是被装饰的函数
end = time.time()
print(end - start)
return ret
return inner # 注意这里是返回内部函数名,不带括号
@timmer
def func(a): #
print("Hello Python", a)
return '你好,世界'
a = func(a) # 注意这里的func()执行的其实是inner函数
print(a)
#-----------------------------------------------------------------------------------------------------------
# 上面只是一个函数并且只有一个参数,那么如果有两个函数,并且是关键字传参等,那么上面这种形式就不行了,下面是这种方法的应对形式
def timmer(function): # 这就是装饰器函数
def inner(*args, **kwargs):
start = time.time()
ret = function(*args, **kwargs) # 这就是被装饰的函数
end = time.time()
print(end - start)
return ret
return inner # 注意这里是返回内部函数名,不带括号
@timmer # python中的语法糖 @装饰器函数名 这里@timmer就相当于执行了 func = timmer(func) @下面紧跟着的就是被装饰函数
def func(a):
print("Hello Python", a)
return '你好,世界'
@timmer
def func1(a, b):
print("Hello Python", a, b)
return '你好'
# func = timmer(func)
a = func(1) # 注意这里的func()执行的其实是inner函数
b = func1(1, 2)
print(a)
print(b)
#=======================================================================================================================#
'''
上面就是装饰器的形成过程,下面是装饰器的固定形式
'''
def wrapper(function): # 这就是装饰器函数,function是被装饰的函数
def inner(*args, **kwargs):
'''这里写被装饰函数之前要做的事'''
ret = function(*args, **kwargs) # 这就是被装饰的函数
'''这里写被装饰函数之后要做的事'''
return ret
return inner # 注意这里是返回内部函数名,不带括号
@wrapper # 等价于 func = wrapper(func)
def func(a):
'''这是一个func函数'''
print("Hello Python", a)
return '你好,世界'
print(func.__name__) # __name__打印函数名,这里打印的是inner,因为经过装饰器装饰后func引用的函数已经不再是原函数了
print(func.__doc__) # 打印文档注释
#=======================================================================================================================#
# 对于被装饰函数,我们不想改变其引用的函数,即我们原本的func函数在被装饰后应该依然是func函数名指的依然是原本的函数,而不是inner函数,那么我们应该怎么做呢?
# 很简单,我们只需要给inner函数使用wraps装饰器装饰一下即可
from functools import wraps
def wrapper(function): # 这就是装饰器函数,function是被装饰的函数
@wraps(function) # 带参数的装饰器
def inner(*args, **kwargs):
'''这里写被装饰函数之前要做的事'''
ret = function(*args, **kwargs) # 这就是被装饰的函数
'''这里写被装饰函数之后要做的事'''
return ret
return inner # 注意这里是返回内部函数名,不带括号
@wrapper
def func(a):
'''这是一个func函数'''
print("Hello Python", a)
return '你好,世界'
print(func(1))
print(func.__name__) # __name__打印函数名,这里打印的就是原先的func了
print(func.__doc__) # 打印 这是一个func函数
#=======================================================================================================================#
# 对于多个装饰器装饰一个函数时
def wrapper1(function):
print("装饰器1")
def inner(*args, **kwargs):
print("inner1")
return function(*args, **kwargs)
return inner
def wrapper2(function):
print("装饰器2")
def inner(*args, **kwargs):
print("inner2")
return function
return inner
@wrapper1
@wrapper2
def func():
print("func函数")
func()
# 打印的结果是: 当多个装饰器装饰一个函数时,执行时的顺序是:最先装饰的装饰器,最后一个执行。它遵循了先进后出这样一个规则
# 装饰器2
# 装饰器1
# inner1
# inner2
#=======================================================================================================================#
# 带参数的装饰器(即三层装饰器)
FLAG = True # 设置全局变量,控制装饰器是否工作
def wrapper_out(flag):
def wrapper(function):
def inner(*args, **kwargs):
if flag: # 当flag为True 即全局的FLAG为True时才运行装饰器扩展的功能
'''这里写装饰器扩展的功能'''
print("装饰器工作区域")
rec = function(*args, **kwargs)
return rec
else:
return function(*args, **kwargs)
return inner
return wrapper
@wrapper_out(FLAG) # 这里先运行 wrapper_out(FLAG) 相当于先调用了wrapper_out函数,在@ 即 先wrapper = wrapper_out(FLAG) 再 func = wrapper(func)
def func():
return "你好,python"
@wrapper_out(FLAG)
def func2():
return "你好,java"
print(func())
print(func2())