
本文共 3176 字,大约阅读时间需要 10 分钟。
装饰器(Decorator)是Python中的一个核心概念,它本质上是一个高阶函数,能够在不修改函数定义的前提下,为函数添加额外功能。装饰器的核心特点在于其灵活性和可重用性,便于处理如日志记录、性能监控、事务管理、缓存控制和权限验证等通用场景。通过引入装饰器,开发者可以将与函数本身无关的关注点抽离出来,从而实现代码的可维护性和可重用性。
1. 常见类型分析
1.1 无参数装饰器与无参数被装饰函数
最简单的装饰器类型是无参数装饰器,对应的被装饰函数也不接受参数。这类装饰器容易实现,仅需定义一个嵌套函数来包装被装饰函数。以下是一个典型示例:
def dec1(func): def inner(): print('========2===========') return inner
当使用@dec1
装饰一个不接受参数的函数时,相当于执行以下代码:
func1 = dec1(func1)
函数执行顺序:
dec1
被解释并返回 inner 函数func1
被解释并绑定为 inner 函数- 当
func1()
被调用时,会执行 inner()
1.2 无参数装饰器与有参数被装饰函数
当被装饰函数接受参数时,无参数装饰器需要更新其内部函数来接收并传递这些参数。这样可以通过扩展装饰器的内部函数来支持可变参数:
def dec2(func): def inner(*args, **kwargs): print('========2===========') return inner(*args, **kwargs)( func(*args, **kwargs) )
当使用@dec2
装饰一个带参数的函数时,相当于执行以下代码:
func2 = dec2(func2)func2('hello', 'world')
函数执行顺序:
dec2
被解释并返回 inner 升级版本func2
被解释并绑定为 inner 升级版本- 当
func2('hello', 'world')
被调用时,会执行 inner
1.3 带参数装饰器与带参数被装饰函数
外层装饰器接收自己的参数,并返回一个装饰器,这样可以通过外层函数传递参数到内部。这种设计允许装饰器本身携带功能参数:
def outer(arg): arg = str(arg) print(arg)def dec3(func): def inner(*args, **kwargs): print('========2===========') return func(*args, **kwargs) return inner
当使用@outer('带参数装饰器')
装饰一个带有参数的函数时,相当于执行以下代码:
from outer import inner, func3func3 = outer('带参数装饰器')(func3)
函数执行顺序:
outer
被解释并打印传入参数dec3
被解释并返回 innerfunc3
被解释并绑定为 inner
1.4 类装饰器(无参数)
类装饰器通过__call__
方法实现装饰逻辑。类装饰器不自身带参数,但可以通过实例属性存储被装饰函数:
class Decorator1(object): def __init__(self, func): self.func = func def __call__(self): print('这是不接受参数的类装饰器') self.func()
当使用@Decorator1
装饰一个无参数函数时,相当于执行以下代码:
from functools import partialfunc6 = partial(Decorator1(func6))
1.5 类装饰器(带参数)
类装饰器需要支持参数,同时可以处理有参数的被装饰函数。实现方法是将参数存储在实例中,并在__call__
中传递:
class Decorator2(object): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print('这是接受参数的类装饰器') return self.func(*args, **kwargs)
当使用@Decorator2
装饰一个带参数的函数时,相当于执行以下代码:
from functools import partialfrom functools import wraps@Decorator2(func7)func7 = wraps(func7)
1.6 带参数的类装饰器
更复杂的装饰器可能需要同时携带自己的参数和被装饰函数的参数:
class Decorator3(object): def __init__(self, x, y): self.x = x self.y = y def __call__(self, func, *args, **kwargs): print('这是接受参数的类装饰器,而且装饰器也带参数') def wrapper(*args, **kwargs): print(self.x, self.y) return func(*args, **kwargs) return wrapper
当使用@Decorator3('d1', 'd2')
装饰一个带参数的函数时,相当于执行以下代码:
from functools import partialfrom functools import wraps@Decorator3('d1', 'd2')func8 = wraps(func8)
2. 使用 functools.wraps
为了使装饰器更友好地与被装饰函数配合,可以使用functools.wraps
装饰器。它不仅保留了被装饰函数的名字和文档,还优化了函数的可读性:
from functools import wrapsdef dec4_nowraps(func): @wraps(func) def inner(): print('函数名为:', func.__name__) return inner
from functools import wraps@dec4_nowrapsdef func4(): print('函数名为:', func4.__name__) print('函数名为:', inner.__name__)
from functools import wraps@wraps(func5)def func5(): print('函数名为:', func5.__name__) print('函数名为:', func5.__name__)
总结
装饰器作为Python中的核心设计模式,极大地简化了函数扩展的复杂性。其灵活性和可扩展性使其成为现代应用开发的重要工具。通过合理选择和配置装饰器的类型,可以有效应对各种场景需求。在实际应用中,建议根据具体需求选择合适的装饰器类型,并谨慎处理参数和状态。
发表评论
最新留言
关于作者
