page contents

Python装饰器详解,看完终于理解它了!

装饰器是Python中最强大但也最难理解的概念之一。很多人被它绕晕了。今天用最直白的方式,让你彻底搞懂装饰器的原理和实战用法!

attachments-2026-05-HkJiqW0Z6a03db279a069.png

装饰器是Python中最强大但也最难理解的概念之一。很多人被它绕晕了。今天用最直白的方式,让你彻底搞懂装饰器的原理和实战用法!

P1:装饰器的本质——函数即对象

理解装饰器之前,先要明白一个核心概念:Python中函数也是对象,可以像变量一样传递。这是一切的基础。

函数作为返回值:

def outer():          
    def inner():          
        print('inner执行了')          
    return inner  # 返回函数对象,不是调用它          

result = outer()  # result现在就是inner函数          
result()  # 调用result,执行inner          
# 输出:inner执行了

函数作为参数:

def add(a, b):          
    return a + b          

def multiply(a, b):          
    return a * b          

def apply_twice(func, x, y):          
    return func(func(x, y), func(x, y))          

print(apply_twice(add, 1, 2))      # (1+2)+(1+2) = 6          
print(apply_twice(multiply, 2, 3)) # (2*3)*(2*3) = 36

P2:手写第一个装饰器——理解原理

装饰器本质上就是一个"包装"函数。它接收一个函数作为参数,返回一个新的函数,在不改变原函数的基础上添加新功能。

最简单的装饰器:

def my_decorator(func):          
    def wrapper(*args, **kwargs):          
        print('=== 调用前 ===')          
        result = func(*args, **kwargs)# 调用原函数          
        print('=== 调用后 ===')          
        return result          
    return wrapper          

@my_decorator          
def say_hello(name):          
    print(f'你好,{name}!')          

say_hello('Rose')          
# 输出:          
# === 调用前 ===          
# 你好,Rose!          
# === 调用后 ===

P3:实战装饰器——计时器、登录验证、日志

装饰器最大的价值是"横切关注点分离":把分散在多个函数中的重复逻辑(计时、认证、日志)抽离出来,统一处理。

装饰器1:函数计时器

import time          
from functools import wraps          

def timer(func):          
    @wraps(func)# 保留原函数元数据          
    def wrapper(*args, **kwargs):          
        start = time.time()          
        result = func(*args, **kwargs)          
        elapsed = time.time() - start          
        print(f'{func.__name__} 执行耗时: {elapsed:.4f}秒')          
        return result          
    return wrapper          

@timer          
def slow_function():          
    time.sleep(1)          
    return '完成'          

slow_function()  # slow_function 执行耗时: 1.0004秒

装饰器2:登录验证

from functools import wraps          

def login_required(func):          
    @wraps(func)          
    def wrapper(*args, **kwargs):          
        if not getattr(func, 'is_logged_in', False):          
            print('❌ 请先登录!')          
            return None          
        return func(*args, **kwargs)          
    # 模拟登录标记          
    wrapper.is_logged_in = True          
    return wrapper          

@login_required          
def get_profile():          
    print('✅ 获取用户资料...')          

get_profile()  # ✅ 获取用户资料...

装饰器3:日志记录器

import logging          

logging.basicConfig(level=logging.INFO)          
logger = logging.getLogger(__name__)          

def log_calls(func):          
    @wraps(func)          
    def wrapper(*args, **kwargs):          
        logger.info(f'调用 {func.__name__},参数: {args}, {kwargs}')          
        try:          
            result = func(*args, **kwargs)          
            logger.info(f'{func.__name__} 返回: {result}')          
            return result          
        except Exception as e:          
            logger.error(f'{func.__name__} 异常: {e}')          
            raise          
    return wrapper

P4:装饰器传参——带参数的装饰器工厂

如果装饰器本身需要参数,需要再包一层函数来接收参数,这叫"装饰器工厂"。

带参数的装饰器:

def repeat(times):  # 接收装饰器参数          
    def decorator(func):# 接收被装饰函数          
        @wraps(func)          
        def wrapper(*args, **kwargs):          
            for _ in range(times):          
                result = func(*args, **kwargs)          
            return result          
        return wrapper          
    return decorator          

@repeat(times=3)          
def say_hi():          
    print('Hi!')          

say_hi()  # 输出3次'Hi!'

@wraps的作用:保留原函数的__name__、__doc__等元数据,不用@wraps的话,装饰后函数名会变成wrapper。

P5:总结

今天彻底讲透了Python装饰器,从原理到实战一网打尽。核心要点:          

1. 函数即对象:函数可以赋值给变量、作为参数、作为返回值,这是装饰器的基础;
2. 装饰器本质:一个返回函数的函数,接收原函数作为参数,在不修改原函数的情况下添加新功能;
3. @wraps必须用:保留被装饰函数的元数据(名字、文档字符串),避免调试困扰 
4. args/kwargs:wrapper函数用*args/**kwargs接收任意参数转发给原函数;
5. 装饰器工厂:如果装饰器需要参数,再包一层函数返回装饰器;
6. 实战场景:计时器(性能分析)、登录验证(权限控制)、日志(行为追踪)、重试机制(容错处理)。

实践建议:不要为了用装饰器而用装饰器。当你在多个函数中写重复的前后置逻辑(如检查参数、记录日志、测量时间)时,就是抽取成装饰器的最佳时机。装饰器是代码重复的克星,用好了事半功倍!

更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

 

  • 发表于 2026-05-13 10:00
  • 阅读 ( 23 )
  • 分类:Python开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

2059 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 2228 文章
  3. Pack 2059 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章