企业网站形象建设什么是百度竞价
装饰器(Decorator) 是 Python一种强大的语法特性,允许在不修改原函数或类代码的前提下,动态地扩展其功能。和其名字一样,装饰器的核心思想就是"包装",即通过将函数或类作为参数传递给另一个函数(装饰器),返回一个增强后的新函数或类。
核心概念
-
函数是一等对象
Python 中函数可以像变量一样传递、赋值或作为返回值,这是装饰器的基础。 -
闭包(Closure)
内部函数可以访问外部函数的变量,即使外部函数已执行完毕。 -
语法糖
@
@decorator
等价于func = decorator(func)
,简化装饰器的应用。
示例
def my_decorator(func):def wrapper():print("函数执行前...")func()print("函数执行后...")return wrapper@my_decorator
def say_hello():print("Hello!")say_hello()
输出:![]()
原理
装饰器的本质是函数嵌套,@my_decorator 等价于:
say_hello = my_decorator(say_hello)
如何处理带参数的函数
函数可以使用 *args
和 **kwargs
接受任意参数:
def my_decorator(func):def wrapper(*args, **kwargs):print(f"参数: args={args}, kwargs={kwargs}")return func(*args, **kwargs)return wrapper@my_decorator
def add(a, b):return a + bprint(add(3, b=4))
输出:
如何保留原函数元信息
如果不使用functools.wraps,被装饰的函数的名称、文档字符串等会被替换,可能导致调试困难。因此,应该使用functools.wraps来保留原函数的元数据。
from functools import wraps
import timedef my_decorator(func):@wraps(func) # 使用@wraps保留原函数信息def wrapper(*args, **kwargs):import timestart = time.time()result = func(*args, **kwargs)end = time.time()print(f"{func.__name__} 执行耗时: {end - start:.2f}秒")return resultreturn wrapper@my_decorator
def my_func():"""模拟耗时操作"""time.sleep(1)my_func()
print(my_func.__name__)
输出:
编辑
如果不使用@wraps,则会输出 wrapper
带参数的装饰器
装饰器本身是可以接受参数的,但需要多一层嵌套:
from functools import wrapsdef repeat(n):"""重复执行函数 n 次"""def decorator(func):@wraps(func)def wrapper(*args, **kwargs):for _ in range(n):result = func(*args, **kwargs)return resultreturn wrapperreturn decorator@repeat(5)
def greet(name):print(f"Hello, {name}!")greet("Tom")
输出:![]()
类装饰器
类也可以作为装饰器,需实现 __call__
方法:
class Test:def __init__(self, func):self.func = funcself.calls = 0def __call__(self, *args, **kwargs):self.calls += 1print(f"函数 {self.func.__name__} 被调用了第 {self.calls} 次")return self.func(*args, **kwargs)@Test
def say_hi():print("Hi!")say_hi()
say_hi()
输出:
装饰器的应用场景
-
日志记录
记录函数调用参数、返回值或异常。 -
性能计时
统计函数执行时间。 -
权限校验
在 Web 框架中检查用户权限(如 Flask/JWT)。 -
缓存结果
缓存函数结果避免重复计算(如@lru_cache
)。 -
路由注册
Web 框架中用装饰器定义路由(如 Flask 的@app.route
)。
注意事项
-
装饰器顺序
如果使用一个装饰器装饰另一个装饰器,是按从下到上的顺序执行:@decorator1 @decorator2 def func():pass
等价于 func = decorator1(decorator2(func))
-
不要影响原函数行为
确保装饰器不要影响原函数的行为,如参数、返回值等。 -
正确使用wraps保留元信息
在使用装饰器时,要正确使用functools.wraps
保留元信息,方便调试。
码字不易,原创更不易,如您觉得本文对您有帮助,麻烦动动您富贵的小手,点赞、收藏、关注、订阅!!!