理解 Python 装饰器:@ 的强大功能
·
文章目录
理解 Python 装饰器:@ 的强大功能
在 Python 中,@ 符号与**装饰器(Decorator)**紧密相关。装饰器是一种强大且灵活的工具,允许在不修改函数、方法或类源代码的情况下,扩展或修改其行为。本文将深入探讨装饰器的工作原理、执行时机以及实际应用,结合通用 Python 编程和 FastAPI 框架的示例。
什么是装饰器?
装饰器是一个高阶函数(或可调用对象),通过包装另一个函数或类来添加功能。Python 的 @ 符号是装饰器的语法糖,用于简洁地应用装饰器。例如:
def my_decorator(func):
def wrapper():
print("函数调用前")
func()
print("函数调用后")
return wrapper
@my_decorator
def say_hello():
print("你好!")
say_hello()
输出:
函数调用前
你好!
函数调用后
在这里,@my_decorator 将 say_hello 函数包装在一个 wrapper 函数中,添加了调用前后打印日志的功能。@ 语法等价于:
say_hello = my_decorator(say_hello)
装饰器何时执行?
装饰器的执行分为两个阶段:
- 代码解析阶段(模块加载时):
- 当 Python 加载模块时,遇到
@decorator,会立即执行装饰器函数(例如my_decorator),将目标函数(例如say_hello)作为参数传递,并返回一个新的函数(例如wrapper)。 - 这一阶段负责装饰器的注册或配置。
- 示例:
- 当 Python 加载模块时,遇到
import time
from functools import wraps
def timer_decorator(func):
print("解析时执行:注册装饰器")
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__} 耗时 {time.time() - start_time:.2f} 秒")
return result
return wrapper
@timer_decorator
def slow_function():
time.sleep(1)
return "完成"
print("正在解析代码...")
slow_function()
输出:
解析时执行:注册装饰器
正在解析代码...
slow_function 耗时 1.00 秒
print("解析时执行:注册装饰器")在模块加载时打印,表明装饰器的外层逻辑在解析时执行。
- 运行时阶段:
- 被包装的函数(
wrapper)只有在调用被装饰函数(例如slow_function())时才会执行。 - 在上述示例中,
wrapper的计时逻辑(记录时间并打印)在slow_function()调用时运行。
- 被包装的函数(
装饰器实战:FastAPI
装饰器在 FastAPI 框架中被广泛用于路由和事件处理。以下是具体分析。
FastAPI 的 @app.get
在 FastAPI 中,@app.get 是一个装饰器,用于将函数绑定到特定的 HTTP 路由。例如:
from fastapi import FastAPI
app = FastAPI()
@app.get("/hello")
@app.get("/v1/hello")
async def hello():
return {"message": "你好!"}
- 解析阶段:
- Python 解析代码时,
@app.get("/hello")和@app.get("/v1/hello")调用FastAPI.get方法,进而调用app.add_api_route,将hello函数注册到app.routes路由表,分别对应/hello和/v1/hello。 - 此时没有处理任何 HTTP 请求,装饰器仅完成路由配置。
- Python 解析代码时,
- 运行时阶段:
- 当收到
GET /hello或GET /v1/hello请求时,FastAPI 查询app.routes,找到匹配的hello函数并直接调用。装饰器的逻辑(路由注册)不会再次执行。
- 当收到
- 多个装饰器:
- 多个
@app.get装饰器按从下到上的顺序应用:@app.get("/v1/hello")将hello注册到/v1/hello。@app.get("/hello")将hello注册到/hello。- 两个路由都指向同一个
hello函数,请求任一路径都会触发它。
- 多个
FastAPI 的 @app.on_event
FastAPI 曾使用 @app.on_event 装饰器来处理启动或关闭事件。例如:
@app.on_event("startup")
async def startup_event():
print("应用启动...")
- 解析阶段:
@app.on_event("startup")调用FastAPI.on_event,将startup_event注册到启动事件处理列表。 - 运行时阶段:应用启动时,FastAPI 调用所有注册的启动事件函数。
注意:
@app.on_event在 FastAPI 新版本中已废弃,推荐使用lifespan机制。例如:
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: FastAPI):
print("应用启动...")
yield
print("应用关闭...")
app = FastAPI(lifespan=lifespan)
关于装饰器的关键点
- 不限于函数:装饰器可以应用于函数、方法或类,只要它们是可调用对象(类需实现
__call__)。 - 多个装饰器:多个装饰器按从下到上的顺序应用(由内向外)。例如:
@decorator1
@decorator2
def my_function():
print("函数执行")
-
decorator2先包装my_function,decorator1再包装decorator2的结果。 -
解析与运行时:
- 解析时:执行装饰器的外层逻辑(注册、配置)。
- 运行时:执行包装逻辑(例如计时、路由处理)。
-
FastAPI 特性:
@app.get在解析时注册路由(调用app.add_api_route),运行时直接调用目标函数。
结论
Python 的 @ 装饰器是一种优雅的工具,能够增强代码的模块化和可重用性。无论是记录函数执行时间、注册 FastAPI 路由,还是实现权限控制,装饰器都提供了简洁的方式在不修改原始代码的情况下添加功能。
更多推荐

所有评论(0)