当前位置:首页>python>Python 装饰器入门——10 行代码理解 @decorator 的原理与实战

Python 装饰器入门——10 行代码理解 @decorator 的原理与实战

  • 2026-10-11 08:28:49
Python 装饰器入门——10 行代码理解 @decorator 的原理与实战

你写 Python 时有没有见过这种语法,函数上面顶着一个 @something,不知道是什么意思?

这就是 Python 的装饰器(Decorator),Flask、Django、FastAPI 等主流框架里随处可见它的身影。

很多人觉得装饰器神秘难懂,其实原理超级简单。今天用 10 行核心代码,带你彻底搞明白它。

前置知识

Python 函数也是"对象"

要理解装饰器,先要知道一件事:Python 里函数也是对象,可以像变量一样传来传去,也可以作为参数传给另一个函数。

🐍 函数作为变量

def say_hello():

    print("Hello!")

# 函数可以赋值给变量

greet = say_hello

greet() # 输出:Hello!

# 函数可以作为参数传入另一个函数

def run(func):

    func()

run(say_hello) # 输出:Hello!

💡 理解了"函数是对象",装饰器就自然明白了。

原理

装饰器到底是什么?

装饰器就是一个接收函数、返回新函数的函数。它能在不修改原函数代码的情况下,给函数"套一层外衣",添加新功能。

🔧 手动实现一个计时装饰器

import time

# 这就是一个装饰器函数

def timer(func): # ① 接收一个函数

    def wrapper():

        start = time.time()

        func() # ② 调用原函数

        end = time.time()

        print(f"耗时:{end-start:.3f}s")

    return wrapper # ③ 返回新函数

# 手动使用:把函数"包裹"起来

def slow_task():

    time.sleep(1)

slow_task = timer(slow_task) # 手动包裹

slow_task() # 输出:耗时:1.001s

✅ 看清楚了吗?装饰器就是把原函数"塞进"一个新函数里,新函数在调用原函数的前后可以做额外的事情。

语法糖

@ 符号让写法更优雅

slow_task = timer(slow_task) 这种写法太繁琐。Python 提供了 @ 语法糖,两行变一行:

✨ 使用 @ 语法糖(效果完全一样)

@timer # 等同于 slow_task = timer(slow_task)

def slow_task():

    time.sleep(1)

slow_task() # 输出:耗时:1.001s

❌ 不用 @ 的写法

def slow_task():

  ...

slow_task = timer(slow_task)

✅ 用 @ 的写法

@timer

def slow_task():

  ...

💡 @ 只是语法糖,背后做的事情完全一样。理解了原理,就不会再对 @ 感到神秘!

进阶

让装饰器支持有参数的函数

如果被装饰的函数有参数,需要在 wrapper 里用 *args, **kwargs 接收并传递:

🔧 通用计时装饰器(支持任意参数)

def timer(func):

    def wrapper(*args, **kwargs): # 接收任意参数

        start = time.time()

        result = func(*args, **kwargs) # 传递参数

        print(f"{func.__name__} 耗时:{time.time()-start:.3f}s")

        return result # 保留返回值

    return wrapper

@timer

def add(a, b):

    return a + b

print(add(3, 5))

# add 耗时:0.000s

# 8

实战

3 个超实用装饰器场景

🔐 场景一:登录状态校验

def login_required(func):

    def wrapper(*args, **kwargs):

        if not is_logged_in():

            return "请先登录"

        return func(*args, **kwargs)

    return wrapper

@login_required

def view_profile():

    return "个人主页内容"

🔄 场景二:自动重试(网络请求失败时)

def retry(times=3): # 带参数的装饰器

    def decorator(func):

        def wrapper(*args, **kwargs):

            for i in range(times):

                try:

                    return func(*args, **kwargs)

                except Exception as e:

                    print(f"第{i+1}次失败:{e}")

        return wrapper

    return decorator

@retry(times=3) # 失败自动重试3次

def fetch_data(url):

    # 发起网络请求...

⚡ 场景三:用 Python 内置的缓存装饰器

from functools import lru_cache

@lru_cache(maxsize=128) # 自动缓存计算结果

def fibonacci(n):

    if n <= 1:

        return n

    return fibonacci(n-1) + fibonacci(n-2)

# 重复调用直接读缓存,速度飞快

print(fibonacci(35)) # 9227465

💡 lru_cache 是 Python 标准库自带的缓存装饰器,递归函数加上它性能提升几十倍!

📋 装饰器知识速查

概念

说明

装饰器本质

接收函数、返回新函数的函数

@ 符号

语法糖,等同于 f = dec(f)

*args **kwargs

让装饰器适配任意参数的函数

functools.wraps

保留原函数名称和文档

lru_cache

内置缓存装饰器,提速利器

叠加装饰器

多个 @ 从下往上依次包裹

🛠️ 动手挑战

试着自己写一个日志装饰器,要求:

① 在函数执行前打印:正在调用 xxx 函数...

② 在函数执行后打印:xxx 函数执行完毕

③ 支持任意参数的函数

🎯 提示:用 func.__name__ 可以获取函数名。写好后在评论区分享你的代码吧!

— 下期预告 —

用 Python 做一个简单的聊天机器人

调用免费 AI 接口,30 行代码实现命令行对话

——敬请期待

奥饼饼智慧谷 · 每天一点编程趣味

❤️ 如果对你有帮助,欢迎转发给身边学编程的朋友~

最新文章

随机文章