拓冰建站拓冰建站
首页 / 资讯中心 / 正文

FastAPI 官方教程精读:Python 类型提示(Type Hints)入门及其在 FastAPI 中的威力

FastAPI 官方教程精读Python 类型提示Type Hints入门及其在 FastAPI 中的威力【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi本篇导读本文对应本仓库 FastAPI 韩文官方文档 python-types.md其内容同源于英文官方文档 Python Types Intro系统讲解 Python类型提示Type Hints又称类型注解的核心语法并揭示它为什么是 FastAPI 的地基——请求解析、数据校验、自动错误与 OpenAPI 文档全部建立在类型提示之上。读完本文你将掌握函数参数注解、内建泛型容器、Union、None可选值、类即类型、Pydantic 模型与Annotated元数据这六大用法并能立即迁移到 FastAPI 的路径操作函数中。Python 是一门可选地支持type hints类型提示也叫 type annotations的语言。所谓类型提示是一类特殊的语法用来声明某个变量的类型例如str、int、float、bool。一旦变量有了明确的类型声明编辑器与各类开发工具就能提供远超普通脚本的开发体验。本文是一份面向 FastAPI 使用场景的快速教程 / 知识回顾只讲你真正需要的最少内容——事实上真的非常少。FastAPI 整个框架都建立在类型提示之上它也因此获得了大量好处。即使你完全不用 FastAPI花几分钟学会类型提示也会很有价值。[!NOTE] 如果你已经精通 Python 类型提示可以直接跳到下一章教程 - 用户指南。本文面向刚接触该概念的读者。动机从一个简单例子说起先看一个最简单的程序对应仓库示例 docs_src/python_types/tutorial001_py310.pydef get_full_name(first_name, last_name): full_name first_name.title() last_name.title() return full_name print(get_full_name(john, doe))运行它会输出John Doe这个函数做的事情只有三件接收first_name与last_name两个参数通过字符串方法title()把每个单词首字母转为大写在中间加一个空格把两者拼接concatenate起来。试着从零编写这段代码如果这段程序是你从头开始写的会发生什么在你开始编写函数、准备好参数之后你需要在某个时刻调用那个把首字母转为大写的方法。它是upper吗是uppercasefirst_uppercase还是capitalize接下来是每个开发者都熟悉的动作——在编辑器里按自动补全。输入函数第一个参数first_name敲一个点.然后按下CtrlSpace触发补全。然而遗憾的是编辑器此刻什么有用的提示都给不出来原因很简单编辑器不知道first_name到底是什么类型因此也无法列出字符串对象上的方法。而这就是类型提示要解决的问题。加上类型只改一行我们把上一版代码中函数参数的声明first_name, last_name改成first_name: str, last_name: str仅此而已。这就是类型提示完整示例见 docs_src/python_types/tutorial002_py310.pydef get_full_name(first_name: str, last_name: str): full_name first_name.title() last_name.title() return full_name print(get_full_name(john, doe))请注意这与给参数赋默认值的写法完全不同first_namejohn, last_namedoe类型提示用的不是等号而是冒号:它不改变函数的任何运行时行为。通常情况下加了类型提示之后发生的事与不加类型提示时相比没有任何区别——类型提示是给开发者、编辑器与静态分析工具看的契约而非运行时的强制约束。但好处立竿见影当我们再次从头编写这个函数并在同样的位置按下CtrlSpace触发自动补全时编辑器会列出str类型提供的全部方法只需滚动浏览这些选项你就能找回那个想不起来的正确方法名更大的动机不止补全还能纠错仅仅自动补全还不够有说服力再看一个已经带类型提示的函数示例见 docs_src/python_types/tutorial003_py310.pydef get_name_with_age(name: str, age: int): name_with_age name is this old: age return name_with_age因为编辑器知道age的类型是int它不仅能补全还能执行类型检查直接在你写代码时划出红线——把int直接拼接到字符串上显然是一个错误于是你立刻知道这里需要修正把age用str(age)转换成字符串def get_name_with_age(name: str, age: int): name_with_age name is this old: str(age) return name_with_age见修正版示例 docs_src/python_types/tutorial004_py310.py。这正是类型 编辑器组合的价值把本应到运行时才能暴露的错误提前到敲击键盘的瞬间。在哪里声明类型刚才我们看到了类型提示最主要的声明位置——函数参数。对 FastAPI 而言这也是最核心的位置你在路径操作函数里为每个参数写下的类型注解直接决定了框架如何处理它们详见下文FastAPI 中的类型提示。简单类型除了str你可以声明 Python 的一切标准类型例如int、float、bool、bytes。一个同时包含多种简单类型参数的函数示例见 docs_src/python_types/tutorial005_py310.pydef get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes): return item_a, item_b, item_c, item_d, item_etyping模块在少数补充场景下你需要从标准库的typing模块导入某些类型。例如要声明一个值可以是任何类型可以使用typing中的Anyfrom typing import Any def some_function(data: Any): print(data)泛型类型Generic Types还有一类类型可以接收类型参数写在方括号[]内部以刻画容器内元素的类型例如字符串的列表就声明为list[str]。这类支持类型参数的类型被称为Generic types泛型。Python 内置容器都可以按泛型方式使用listtuplesetdictlist例如声明一个元素类型为str的列表变量。语法与之前完全一致——用冒号:声明类型写list由于list是含有内部类型的类型把这些内部类型放进方括号里即可def process_items(items: list[str]): for item in items: print(item)见 docs_src/python_types/tutorial006_py310.py[!NOTE] 方括号中的内部类型称为type parameters类型参数。这里的str就是传给list的类型参数。这句话的含义是变量items是一个list其中每一个元素都是str。这样即使是在遍历列表、处理单个元素的代码中编辑器也能持续提供支持——上例中循环内的item是items的一个元素编辑器依然知道它是str从而给出字符串方法的相关补全。没有类型提示时这几乎是不可能的。tuple与settuple与set的声明方式完全相同见 docs_src/python_types/tutorial007_py310.pydef process_items(items_t: tuple[int, int, str], items_s: set[bytes]): return items_t, items_s它表达的意思是变量items_t是包含 3 个元素的tuple分别是int、又一个int、以及str变量items_s是一个set其中每个元素的类型是bytes。dict声明dict时需要传入两个以逗号分隔的类型参数第一个描述键key的类型第二个描述值value的类型见 docs_src/python_types/tutorial008_py310.pydef process_items(prices: dict[str, float]): for item_name, item_price in prices.items(): print(item_name) print(item_price)含义是变量prices是一个dict它的键是str例如每个商品的名字它的值是float例如每个商品的价格。Union联合类型你还可以声明一个变量是若干类型中的任意一种例如int或str。在 Python 3.10 中用竖线|分隔多个类型即可这里的|也叫按位或运算符但在此语境下与位运算无关只表示类型的并集。因为变量的类型落在两个类型集合的并集union之内故称为union联合类型def process_item(item: int | str): print(item)见 docs_src/python_types/tutorial008b_py310.py。它表示参数item可以是int也可以是str。注意到仓库示例文件统一使用_py310后缀命名——即这些语法int | str、list[str]等要求 Python 3.10 及以上版本。可能为None的情形联合类型最常见的实战场景之一是这个值可能是某个类型也可能什么都没有。把str | None用作注解就能让编辑器在你假设值总是str、实际却可能为None的地方帮你发现潜在错误。下面是一个带默认值None的函数def say_hi(name: str | None None): if name is not None: print(fHey {name}!) else: print(Hello World)见 docs_src/python_types/tutorial009_py310.py。say_hi可以被无参数调用此时name为None函数打印Hello World也可以传入字符串打印问候语。把类本身用作类型你也可以把自定义的类当作类型来声明变量。假设有一个带名字的Person类class Person: def __init__(self, name: str): self.name name见 docs_src/python_types/tutorial010_py310.py 第 1~3 行那么你可以声明一个类型为Person的变量def get_person_name(one_person: Person): return one_person.name同一文件第 6 行起。随后在函数体内编辑器就能对one_person提供完整的属性与方法补全。这里的语义要特别注意one_person是Person类的一个实例instance而不是Person这个类本身。这一点在 Pydantic 模型一节会更加清晰。Pydantic 模型用类描述数据的形状Pydantic 是一个专注于数据校验的 Python 库你用带属性的类声明数据的形状shape每个属性都带一个类型随后用一组值创建该类的实例Pydantic 会校验这些值、必要时把它们转换为正确的类型最终交给你一个携带全部数据的对象——之后编辑器又能对该对象提供完整支持。来看 Pydantic 官方文档中的经典示例仓库对应文件 docs_src/python_types/tutorial011_py310.pyfrom datetime import datetime from pydantic import BaseModel class User(BaseModel): id: int name: str John Doe signup_ts: datetime | None None friends: list[int] [] external_data { id: 123, signup_ts: 2017-06-01 12:22, friends: [1, 2, b3], } user User(**external_data) print(user) # User id123 nameJohn Doe signup_tsdatetime.datetime(2017, 6, 1, 12, 22) friends[1, 2, 3] print(user.id) # 123请留意这个示例里的自动转换能力id被声明为int传入的123是字符串Pydantic 自动将其转换为整数123signup_ts被声明为datetime | None传入的2017-06-01 12:22字符串被解析为datetime对象friends被声明为list[int]列表中混入的字符串2与字节串b3都被统一转换为整数1, 2, 3。FastAPI 完全建立在 Pydantic 之上。你在 FastAPI 路径操作函数中声明请求体模型时使用的正是这种BaseModel子类——框架接手校验与类型转换而你只需要按标准 Python 类型的方式描述数据。这些内容会在 教程 - 用户指南 中被反复用到仓库内对应的可运行示例位于 docs_src/body、docs_src/body_nested_models 等目录。带元数据的类型提示AnnotatedPython 还提供了一种能力通过Annotated给类型提示附加元数据metadata即关于数据的数据——这里指关于类型的信息例如说明文字。Annotated从typing导入用法如下见 docs_src/python_types/tutorial013_py310.pyfrom typing import Annotated def say_hello(name: Annotated[str, this is just metadata]) - str: return fHello {name}这里有两个关键认知Python 本身不会对Annotated做任何处理——对编辑器和其他工具而言类型依然是strthis is just metadata 只是附加说明但你可以利用Annotated里的这段留白区域向FastAPI 传达你希望应用如何运转的额外元数据。务必记住的核心规则传给Annotated的第一个类型参数才是真正的类型其余参数都只是供其他工具消费的元数据。对 FastAPI 来说Annotated[str, ...]这种写法在后续章节例如用Query、Path、Body、依赖注入等描述参数语义中会展现出惊人的威力——这正是 FastAPI 在较新版本官方教程中力推的声明风格。[!TIP] 由于Annotated是标准 Python特性你依然能在编辑器里获得最佳开发体验代码分析、重构、以及其他大量 Python 工具与库都能与这些注解完美兼容。FastAPI 中的类型提示一套声明四处受益回到本文的核心主题FastAPI 如何利用类型提示当你用类型提示声明 FastAPI 路径操作函数的参数时得到的回报远不止编辑器补全和类型检查。FastAPI 会把这同一份声明同时用于以下四件事定义需求requirements声明请求中的路径参数、查询参数、请求头、请求体、依赖等数据转换data conversion把来自请求的原始数据转换成你声明的 Python 类型如把请求体 JSON 中的字符串123转成int正如上文 Pydantic 示例所示数据校验data validation在每次请求到达时校验数据数据非法时自动生成返回给客户端的错误响应API 文档documentation借助 OpenAPI 为 API 生成文档并呈现在自动化的交互式文档 UISwagger UI / ReDoc中。这些听起来可能有些抽象但它们的原理你已经全部见过了——类型提示只描述数据的形状而 FastAPI 在框架内部替你完成其余工作。最关键的事实是你只需在一处使用标准 Python 类型而无需引入更多类、装饰器等自定义机制FastAPI 就为你代劳了大量事情。这就是 FastAPI 被设计为基于标准 Python 类型提示的原因也是理解后续 教程 - 用户指南 一切内容的前提。[!NOTE] 学完整个教程、想更系统地深入类型知识的读者可以进一步查阅 mypy 官方维护的《Python 3 类型提示速查表》cheat sheet作为标准类型语法层面的补充资料。小结主题语法要点仓库示例函数参数注解param: str冒号后跟类型tutorial002_py310.py简单内建类型int/float/bool/bytes/strtutorial005_py310.py任意类型from typing import Any正文示例泛型容器list[str]/tuple[int, int, str]/set[bytes]/dict[str, float]tutorial006 ~ tutorial008联合类型int \| strPython 3.10tutorial008b_py310.py可选值str \| Nonetutorial009_py310.py类即类型def f(p: Person)实例而非类本身tutorial010_py310.pyPydantic 模型class User(BaseModel) 属性注解tutorial011_py310.py元数据注解Annotated[str, ...]首个参数才是真类型tutorial013_py310.py所有示例代码均可在仓库 docs_src/python_types 目录下找到并直接运行本文相关原始翻译文档位于 docs/ko/docs/python-types.md。掌握这些类型提示语法之后下一步就是进入 FastAPI 教程亲眼见证一套类型声明如何同时驱动校验、转换与自动文档——那是 FastAPI 一切魔法开始的地方。【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门