当前位置: 首页 > news >正文

Python中的装饰器(Decorator) 详解

装饰器(Decorator) 是 Python一种强大的语法特性,允许在不修改原函数或类代码的前提下,动态地扩展其功能。和其名字一样,装饰器的核心思想就是"包装",即通过将函数或类作为参数传递给另一个函数(装饰器),返回一个增强后的新函数或类。

核心概念

  1. 函数是一等对象
    Python 中函数可以像变量一样传递、赋值或作为返回值,这是装饰器的基础。

  2. 闭包(Closure)
    内部函数可以访问外部函数的变量,即使外部函数已执行完毕。

  3. 语法糖 @
    @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 + b

print(add(3, b=4))
输出:

如何保留原函数元信息

如果不使用functools.wraps,被装饰的函数的名称、文档字符串等会被替换,可能导致调试困难。因此,应该使用functools.wraps来保留原函数的元数据。

from functools import wraps
import time

def my_decorator(func):
    @wraps(func)  # 使用@wraps保留原函数信息
    def wrapper(*args, **kwargs):
        import time
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 执行耗时: {end - start:.2f}秒")
        return result
    return wrapper

@my_decorator
def my_func():
    """模拟耗时操作"""
    time.sleep(1)

my_func()
print(my_func.__name__)

输出:
编辑
 
如果不使用@wraps,则会输出 wrapper


带参数的装饰器

装饰器本身是可以接受参数的,但需要多一层嵌套:

from functools import wraps

def repeat(n):
    """重复执行函数 n 次"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for _ in range(n):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(5)
def greet(name):
    print(f"Hello, {name}!")

greet("Tom")
输出:

类装饰器

类也可以作为装饰器,需实现 __call__ 方法:

class Test:
    def __init__(self, func):
        self.func = func
        self.calls = 0

    def __call__(self, *args, **kwargs):
        self.calls += 1
        print(f"函数 {self.func.__name__} 被调用了第 {self.calls} 次")
        return self.func(*args, **kwargs)

@Test
def say_hi():
    print("Hi!")

say_hi() 
say_hi()

输出:

装饰器的应用场景

  1. 日志记录
    记录函数调用参数、返回值或异常。

  2. 性能计时
    统计函数执行时间。

  3. 权限校验
    在 Web 框架中检查用户权限(如 Flask/JWT)。

  4. 缓存结果
    缓存函数结果避免重复计算(如 @lru_cache)。

  5. 路由注册
    Web 框架中用装饰器定义路由(如 Flask 的 @app.route)。

注意事项

  1. 装饰器顺序
    如果使用一个装饰器装饰另一个装饰器,是按从下到上的顺序执行:

    @decorator1
    @decorator2
    def func():
        pass

    等价于 func = decorator1(decorator2(func))

  2. 不要影响原函数行为
    确保装饰器不要影响原函数的行为,如参数、返回值等。

  3. 正确使用wraps保留元信息
    在使用装饰器时,要正确使用 functools.wraps 保留元信息,方便调试。

码字不易,原创更不易,如您觉得本文对您有帮助,麻烦动动您富贵的小手,点赞、收藏、关注、订阅!!!

相关文章:

  • 六十天前端强化训练之第十二天之闭包深度解析
  • 【RK3588嵌入式图形编程】-SDL2-SDL_Image使用详解
  • 3D空间曲线批量散点化软件V1.0正式发布,将空间线条导出坐标点,SolidWorks/UG/Catia等三维软件通用
  • 为什么 MySQL InnoDB 的 Repeatable Read 可以阻止幻读?
  • Django工程获取请求参数的几种方式
  • 一遍通俗易懂的新华三交换机文档指南操作手册
  • AI日报 - 2025年3月10日
  • [项目]基于FreeRTOS的STM32四轴飞行器: 六.2.4g通信
  • ArduPilot开源代码之AP_OSD
  • 基于Python的商品销量的数据分析及推荐系统
  • 使用 Docker 部署 GitLab 并持久化数据
  • comctl32!ListView_OnSetItem函数分析LISTSUBITEM结构中的image表示图标位置
  • 简单的 Python 示例,用于生成电影解说视频的第一人称独白解说文案
  • Oracle数据库监听学习
  • NoteGen是一款开源跨平台的 AI 笔记应用,专注于 recording 和 writing ,基于 Tauri 开发
  • Node.js 技术原理分析系列 4—— 使用 Chrome DevTools 分析 Node.js 性能问题
  • IMX6ULL驱动开发Linux篇02——移植Rootfs
  • 李沐《动手学深度学习》——14.9. 用于预训练BERT的数据集——wiki数据集问题以及存在的其他问题
  • 小白学习:rag向量数据库
  • 《C++ primer》第四章
  • 第十二届警博会在京开幕:12个国家和地区835家企业参展
  • 习近平会见哥伦比亚总统佩特罗
  • 美政府以拨款为要挟胁迫各州服从移民政策,20个州联合起诉
  • 美国4月CPI同比上涨2.3%低于预期,为2021年2月来最小涨幅
  • 乌方:泽连斯基只接受与普京会谈,拒见其他俄代表
  • 美国拟向阿联酋和沙特AI公司出口数十万枚芯片