装饰器
装饰器本质上就是扩展原本函数功能的一种函数,通过函数闭包实现
函数闭包
定义在一个函数中的函数称为函数闭包
闭包三要素
- 函数嵌套,即存在内函数和外函数
- 内函数使用了外函数的变量或者参数
- 外函数需要return内函数
自定义装饰器
def my_decorate(func):
def method(a,b,*args):
print("前置...")
func(a,b) #调用
print("后置...")
print("其它参数:")
for arg in args:
print(arg)
return method
@my_decorate
def add(a,b):
print(f"a + b = {a+b}")
add(1,2,"arg1")
print("\n\n")
#使用@my_decorate等同于,不加装饰器将下面的调用格式转换为add(1,2,"arg1")
#my_decorate(add)(1,2,"arg1")
装饰器的功能增强了原有函数的功能
接收的
func
参数为@下一行的函数
返回装饰器
第二种装饰器是一种高阶装饰器,它返回另一个装饰器。这种装饰器可以接受参数,使得装饰器的行为可以根据传入的参数进行调整。在这个例子中,return_decorate
函数接受一个参数flag
,并返回一个装饰器decorate
。这个装饰器再返回一个包装函数inner
,它在调用原始函数之前打印flag
的值。
def return_decorate(flag):
def decorate(func):
def inner(a, b):
print(f"flag is {flag}")
func(a, b) # 调用
return inner
return decorate
@return_decorate("+")
def add(a,b):
print(f"a + b = {a+b}")
add(1,2)
不同场景返回不同装饰器
def return_decorate(flag):
if flag == '+':
def decorate(func):
def inner(a, b):
print("add!")
func(a, b) # 调用
return inner
return decorate
if flag == '-':
def decorate(func):
def inner(a, b):
print("sub!")
func(a, b)
return inner
return decorate
@return_decorate("+")
def add(a,b):
print(f"a + b = {a+b}")
add(1,2)
两种装饰器的不同点
- 参数传递:第一种装饰器不接受任何参数,它对所有被装饰的函数都是一样的行为。第二种装饰器接受参数,可以根据参数的不同改变装饰器的行为。
- 灵活性:第二种装饰器因为可以接受参数,所以更加灵活。你可以根据需要创建多个具有不同行为的装饰器,而不需要为每种行为编写一个新的装饰器函数。
- 使用方式:第一种装饰器直接应用于函数上,而第二种装饰器需要先调用(传入参数),然后再应用到函数上。
- 装饰器的装饰器:第二种装饰器展示了装饰器的装饰器(即高阶装饰器)的概念,这是Python装饰器的一个高级用法。
装饰器类
使用对象调用被修饰的函数
class MyDecorate(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("前置:装饰器类被调用了")
self.func(*args, **kwargs)
print("后置:装饰器类被调用了")
@MyDecorate
def add(a,b):
print(f"a + b = {a + b}")
add(1,2)
这里的装饰器类,可以大大的增加的代码的通用性,同时需要注意,当类中出现
__call__
魔法方法时,该类大概率为装饰器类。
functools.warp
Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools
包中提供了一个叫wraps的decorator来消除这样的副作用。写一个decorator的时候,最好在实现之前加上functools
的wrap,它能保留原有函数的名称和函数属性
不加wraps
def my_decorator(func):
def wrapper(*args, **kwargs):
'''decorator'''
print('Calling decorated function...')
return func(*args, **kwargs)
return wrapper
@my_decorator
def example():
"""Docstring"""
print('Called example function')
print(example.__name__, example.__doc__) #wrapper decorator
加上warp以后
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
'''decorator'''
print('Calling decorated function...')
return func(*args, **kwargs)
return wrapper
@my_decorator
def example():
"""Docstring"""
print('Called example function')
print(example.__name__, example.__doc__) #example Docstring
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 1300452403@qq.com