python装饰器
发布日期:2021-05-18 03:47:42 浏览次数:15 分类:精选文章

本文共 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, func3
func3 = outer('带参数装饰器')(func3)

函数执行顺序:

  • outer 被解释并打印传入参数
  • dec3 被解释并返回 inner
  • func3 被解释并绑定为 inner

1.4 类装饰器(无参数)

类装饰器通过__call__方法实现装饰逻辑。类装饰器不自身带参数,但可以通过实例属性存储被装饰函数:

class Decorator1(object):
def __init__(self, func):
self.func = func
def __call__(self):
print('这是不接受参数的类装饰器')
self.func()

当使用@Decorator1装饰一个无参数函数时,相当于执行以下代码:

from functools import partial
func6 = 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 partial
from 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 partial
from functools import wraps
@Decorator3('d1', 'd2')
func8 = wraps(func8)

2. 使用 functools.wraps

为了使装饰器更友好地与被装饰函数配合,可以使用functools.wraps装饰器。它不仅保留了被装饰函数的名字和文档,还优化了函数的可读性:

from functools import wraps
def dec4_nowraps(func):
@wraps(func)
def inner():
print('函数名为:', func.__name__)
return inner
from functools import wraps
@dec4_nowraps
def func4():
print('函数名为:', func4.__name__)
print('函数名为:', inner.__name__)
from functools import wraps
@wraps(func5)
def func5():
print('函数名为:', func5.__name__)
print('函数名为:', func5.__name__)

总结

装饰器作为Python中的核心设计模式,极大地简化了函数扩展的复杂性。其灵活性和可扩展性使其成为现代应用开发的重要工具。通过合理选择和配置装饰器的类型,可以有效应对各种场景需求。在实际应用中,建议根据具体需求选择合适的装饰器类型,并谨慎处理参数和状态。

上一篇:linux切换用户执行脚本
下一篇:自动创建linux逻辑卷及扩容

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2025年04月30日 20时03分20秒