FastAPI初识&Python 装饰器学习
1026 字
5 分钟
FastAPI初识&Python 装饰器学习
从 FastAPI 的
@app.get()出发,拆开看看 Python 装饰器到底在干什么。
前言
我一开始是从 FastAPI 的 @app.get() 产生疑问,然后顺着“它到底在修饰谁”“为什么这样写”“装饰器什么时候执行”“带参数装饰器又是什么”这条线,一步一步把 Python 装饰器弄懂。
这篇整理记录的是我的学习过程,先把思路走通,再回头看结论。
1. 最初疑问:FastAPI 路由装饰器

其中的代码:
@app.get("/api/profile")def get_profile(): return profile疑问点 1:@app.get() 和下方 def 是不是绑定在一起?
结论:是的,装饰器只修饰紧随其后的函数。它们在语法上必须连在一起,中间不能插入其他代码。
疑问点 2:谁装饰谁?
@app.get("/api/profile") 装饰的是函数 get_profile。
疑问点 3:装饰器到底有什么用?
它的作用是给普通函数打上“角色标记”,告诉框架:
这个函数用来处理
GET /api/profile的网络请求。
等价的原生写法可以理解为:
def get_profile(): return profile
app.add_api_route(path="/api/profile", endpoint=get_profile, methods=["GET"])所以装饰器本质上是语法糖:把“路径注册”和“业务函数”写在一起,让代码更紧凑、更易读。
2. 切入基础:自定义装饰器(计时器示例)
示例代码:
import time
def timer(function): def wrapper(): time_start = time.time() function() time_end = time.time() cost_time = time_end - time_start print("花费时间:{}秒".format(cost_time)) return wrapper
@timerdef func1(): print('我是一个函数1')关键疑问 1:函数内部为什么还能定义函数?
Python 支持嵌套函数。内层函数可以使用外层函数传进来的变量,这就是闭包的典型表现。
这里可以这样拆:
timer:外层工厂函数wrapper:包装函数,负责新增逻辑(计时)
关键疑问 2:看不见 wrapper() 调用,它是怎么运行的?
把语法糖展开:
@timerdef func1(): pass
# 等价于
def func1(): pass
func1 = timer(func1)执行过程可以分成三步:
- 代码加载阶段(定义时):执行
timer(原始 func1),生成wrapper函数对象; - 变量覆盖:名字
func1不再指向原始函数,而是指向wrapper; - 调用阶段:执行
func1(),实际上就是执行wrapper()。
关键疑问 3:为什么是 return wrapper,不能写 return wrapper()?
这两者完全不同:
return wrapper:返回函数对象本身,后续可以随时调用;return wrapper():立刻执行函数,返回执行结果(大多是None)。
错误示范:
def deco(func): def inner(): print("包装启动") func() return inner() # 当场执行 inner,返回 None
@decodef demo(): print("demo执行")
demo() # 报错 TypeError: 'NoneType' object is not callable3. 随堂测试复盘:易错的时序考点
考题 1
def deco(func): def inner(): print("开始") func() print("结束") return inner
@decodef hello(): print("Hello")
hello()输出:
开始Hello结束理解方式:hello = deco(hello),调用 hello() 时实际执行的是 inner()。
考题 2:时序大坑
def deco(func): print("进入deco") def inner(): print("inner运行") func() return inner
@decodef test(): print("执行test本体")
print("====分割线====")test()正确输出顺序:
进入deco====分割线====inner运行执行test本体核心知识点:@ 装饰器在函数定义阶段就执行外层代码,不等你调用函数。
4. 知识迁移到 FastAPI
回到最开始的代码:
@app.get("/api/profile")def get_profile(): return profile它可以展开成:
def get_profile(): return profile
# 1. app.get 先执行,得到一个装饰器decorator = app.get("/api/profile")
# 2. 使用装饰器包装原始函数get_profile = decorator(get_profile)带参数的装饰器:
app.get("路径")先传入配置;- 然后返回一个专属装饰器;
- 再由这个装饰器去包装业务函数。
执行流程
- 项目启动加载代码:只是在注册路由表;
- 浏览器发起 HTTP 请求访问接口时,FastAPI 自动调用包装后的函数;
- 框架自动把
return的字典转成 JSON,并封装成 HTTP 响应。
我最后记住的是,装饰器的核心就是 @deco 等价于 f = deco(f)。它不是在改原函数的代码,而是把原函数交给另一个函数包一层,再把新的函数返回回来。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!
FastAPI初识&Python 装饰器学习
https://hp-patience.github.io/posts/fastapi-python-decorator-learning/ 相关文章 智能推荐
1
AI辅助学习:把多源知识变成一对一课堂
学习 从 Probe-Plan-Teach 出发,讨论 AI 如何围绕理解边缘、情绪曲线、学习目标和多种练习形式,构建真正的一对一学习体验。
2
Ubuntu 服务器部署 Mihomo 代理完整记录
工具 在 Ubuntu 服务器上部署 Mihomo 代理内核,复用 Clash Verge Rev 订阅配置,并配置 systemd 与命令行代理。
3
在 Linux 服务器上使用 opencode 的正确方式
工具 记录我把 opencode 搬到低配 Linux 服务器上的经历,以及后来改用本地运行、SSH 操作服务器的原因。
4
从 HTML 到 Vite:现代前端开发到底解决了什么问题?
前端 从普通网页的组成讲起,理解现代前端为什么需要模块化、构建工具,以及 Vite 在开发、构建和部署中解决了什么问题。
5
【Claude_Code_CLI安装】代理配置-本地模型-插件生态
工具 Claude Code CLI完整安装指南,涵盖代理配置、DeepSeek/本地模型接入、内网穿透及插件生态。
随机文章 随机推荐