Python装饰器超详细实例教程

 更新时间:2026年05月14日 10:35:20   作者:星哲最开心  
本文介绍了Python装饰器的基本概念、用途和实现方法,装饰器是一种在不修改原函数代码的前提下,为函数动态添加功能的工具,其本质是闭包和高阶函数,装饰器可用于日志记录、计时、权限校验等功能,感兴趣的朋友跟随小编一起看看吧

Python 装饰器是在不修改原函数代码的前提下,给函数动态添加功能的工具,本质是闭包 + 高阶函数,最常用场景:日志记录、计时、权限校验、缓存、事务管理等。

先搞懂 3 个基础概念

装饰器建立在这三个知识点之上,必须先理解:

  1. 函数是一等公民:函数可以作为参数、返回值、赋值给变量
  2. 高阶函数:接收函数作为参数,或返回一个函数
  3. 闭包:内部函数可以访问外部函数的变量,且外部函数执行完毕后变量不销毁

最简单的装饰器(无参函数)

手动实现装饰器(理解原理)

# 定义装饰器:接收一个函数,返回一个新函数
def my_decorator(func):
    def wrapper():
        print("函数执行前:添加额外功能")
        func()  # 调用原函数
        print("函数执行后:添加额外功能")
    return wrapper
# 原函数
def say_hello():
    print("Hello 装饰器!")
# 手动装饰:不修改原函数,给它加功能
say_hello = my_decorator(say_hello)
# 调用
say_hello()

输出

函数执行前:添加额外功能
Hello 装饰器!
函数执行后:添加额外功能

语法糖 @(最常用写法)

Python 提供 @装饰器名 简化写法,效果和上面完全一样

def my_decorator(func):
    def wrapper():
        print("函数执行前")
        func()
        print("函数执行后")
    return wrapper
# 直接用 @ 装饰
@my_decorator
def say_hello():
    print("Hello 装饰器!")
say_hello()

装饰 带参数的函数

如果原函数有参数,装饰器内部的 wrapper 必须能接收参数,用 *args, **kwargs 通用接收:

def my_decorator(func):
    # wrapper 接收任意参数,传给原函数
    def wrapper(*args, **kwargs):
        print("执行前")
        # 调用原函数并传参
        result = func(*args, **kwargs)
        print("执行后")
        # 返回原函数的返回值
        return result
    return wrapper
@my_decorator
def add(a, b):
    return a + b
print(add(10, 20))

输出

执行前
执行后
30

带参数的装饰器(进阶)

装饰器本身也可以接收参数,需要再套一层函数

# 最外层:接收装饰器参数
def decorator_with_param(msg):
    # 中层:真正的装饰器
    def my_decorator(func):
        # 内层:包装函数
        def wrapper(*args, **kwargs):
            print(f"装饰器参数:{msg}")
            result = func(*args, **kwargs)
            return result
        return wrapper
    return my_decorator
# 使用:装饰器带参数
@decorator_with_param("我是自定义参数")
def test():
    print("原函数执行")
test()

保留原函数信息(重要)

直接使用装饰器会覆盖原函数的名字、文档字符串,需要用 functools.wraps 修复:

import functools
def my_decorator(func):
    # 保留原函数信息
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("前置功能")
        return func(*args, **kwargs)
    return wrapper
@my_decorator
def add(a, b):
    """两数相加"""
    return a + b
# 打印原函数名和文档,不会被装饰器覆盖
print(add.__name__)  # 输出 add
print(add.__doc__)   # 输出 两数相加

实战:最常用的 2 个装饰器

计时装饰器(统计函数运行时间)

import time
import functools
def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print(f"函数 {func.__name__} 耗时:{end - start:.4f}s")
        return res
    return wrapper
@timer
def long_task():
    time.sleep(1)
long_task()

日志装饰器(记录函数调用)

import functools
def logger(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f"调用函数:{func.__name__},参数:{args} {kwargs}")
        res = func(*args, **kwargs)
        print(f"函数返回:{res}")
        return res
    return wrapper
@logger
def add(a, b):
    return a + b
add(5, 3)

多个装饰器叠加

多个装饰器执行顺序:从下往上装饰,从上往下执行

def dec1(func):
    def wrapper():
        print("装饰器1 前置")
        func()
        print("装饰器1 后置")
    return wrapper
def dec2(func):
    def wrapper():
        print("装饰器2 前置")
        func()
        print("装饰器2 后置")
    return wrapper
# 执行顺序:dec1前置 → dec2前置 → 原函数 → dec2后置 → dec1后置
@dec1
@dec2
def test():
    print("原函数")
test()

总结

  1. 装饰器作用:不修改原函数,动态添加功能(开闭原则)
  2. 核心结构:外层=装饰器,内层=包装函数(真正执行)
  3. 通用写法*args, **kwargs + functools.wraps
  4. 常用场景:计时、日志、权限、缓存、路由(Flask/Django)

到此这篇关于Python装饰器超详细实例教程的文章就介绍到这了,更多相关Python装饰器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Pytorch各种维度变换函数总结

    Pytorch各种维度变换函数总结

    本文对于PyTorch中的各种维度变换的函数进行总结,包括reshape()、view()、resize_()、transpose()、permute()、squeeze()、unsqeeze()、expand()、repeat()函数的介绍和对比,感兴趣的可以了解一下
    2024-02-02
  • IDEA创建python项目详细图文教程

    IDEA创建python项目详细图文教程

    在开始编写Python代码之前,需要在IDEA中配置Python环境,下面这篇文章主要给大家介绍了关于IDEA创建python项目的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-10-10
  • Python中跳台阶、变态跳台阶与矩形覆盖问题的解决方法

    Python中跳台阶、变态跳台阶与矩形覆盖问题的解决方法

    这篇文章主要给大家介绍了关于Python中跳台阶、变态跳台阶与矩形覆盖问题的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-05-05
  • python面向对象中__new__和__init__区别

    python面向对象中__new__和__init__区别

    在 Python 的面向对象编程中,__new__ 和 __init__ ,它们的职责、执行顺序和返回值完全不同,下面就来详细的介绍一下两者的区别,感兴趣的可以了解下
    2026-04-04
  • Python中装饰器兼容加括号和不加括号的写法详解

    Python中装饰器兼容加括号和不加括号的写法详解

    这篇文章主要给大家介绍了关于Python中装饰器兼容加括号和不加括号写法的相关资料,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-07-07
  • pycharm终端安装pytorch失败的问题及解决

    pycharm终端安装pytorch失败的问题及解决

    这篇文章主要介绍了pycharm终端安装pytorch失败的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-04-04
  • Django初步使用Celery处理耗时任务和定时任务问题

    Django初步使用Celery处理耗时任务和定时任务问题

    这篇文章主要介绍了Django初步使用Celery处理耗时任务和定时任务问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • Python轻松读取TOML文件告别手动编辑配置文件

    Python轻松读取TOML文件告别手动编辑配置文件

    这篇文章主要为大家介绍了Python轻松读取TOML文件告别手动编辑配置文件,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • Django 限制访问频率的思路详解

    Django 限制访问频率的思路详解

    这篇文章主要介绍了Django 限制访问频率的思路详解,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-12-12
  • python 如何将字典写为json文件

    python 如何将字典写为json文件

    这篇文章主要介绍了python 如何将字典写为json文件的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09

最新评论