当前位置: 首页 > news >正文

FastAPI教程I

本文参考FastAPI教程https://fastapi.tiangolo.com/zh/tutorial

第一步

import uvicorn
from fastapi import FastAPIapp = FastAPI()@app.get("/")
async def root():return {"message": "Hello World"}if __name__ == '__main__':uvicorn.run("test:app", host="127.0.0.1", port=8000, reload=True)
$ uvicorn main:app --reload
  • 导入FastAPIFastAPI是一个为你的API提供了所有功能的Python类
  • app = FastAPI()创建一个FastAPI实例,这个实例将是创建你所有API的主要交互对象。这个app同样在如下命令中被uvicorn所引用。
  • 创建一个路径操作。
    【路径】:这里的【路径】指的是从URL中第一个/起的后半部分,比如在https://example.com/items/foo中,路径是/items/foo,【路径】也通常被称为【端点】或【路由】。
    【操作】:这里的【操作】是指一种HTTP【方法】,如POST——创建数据,GET——读取数据,PUT——更新数据,DELETE——删除数据,以及更少见的几种OPTIONS,HEAD,PATCH,TRACE,在HTTP协议中,你可以使用以上的其中一种(或多种)【方法】与每个路径进行通信。
  • 定义一个路径操作装饰器@app.get("/")告诉FastAPI在它下方的函数负责处理如下访问请求:请求路径为/,使用get操作。(@something语法在Python中被称为【装饰器】,接收位于其下方的函数并且用它完成一些工作,这里是路径操作装饰器。)
  • 定义路径操作函数:位于路径操作装饰器下的函数,这里是async def root(),这个例子用的是async函数,其作用在后面讲。
  • 返回内容:可以返回一个dictlist,像strint一样的值,等等。还可以返回Pydanic模型(后面会说),还有许多其他将会自动转换为JSON的对象和模型(包括ORM对象等)。

查看运行结果

  • 打开浏览器访问 http://127.0.0.1:8000。讲看到如下的JSON相应:
{"message": "Hello World"}

交互式API文档

  • 跳转到 http://127.0.0.1:8000/docs。你将会看到自动生成的交互式API文档(由Swagger UI提供)。

可选的API文档

  • 前往 http://127.0.0.1:8000/redoc。你将会看到可选的自动生成文档(由ReDoc提供)。

路径参数

FastAPI支持以下路径模板语法定义动态路由,声明路径参数(变量)

import uvicorn
from fastapi import FastAPIapp = FastAPI()@app.get("/items/{item_id}/{go}")
async def read_item(go):return {"item_id": go}if __name__ == '__main__':uvicorn.run("test:app", host="127.0.0.1", port=8000, reload=True)

这段代码声明了相应位置上的路径参数item_idgo,并把go的值传递给路径函数的参数go

运行示例并访问http://127.0.0.1:8000/items/para1/para2可获得如下相应:

{"item_id":"para2"}

声明路径参数的类型

使用Python标准类型注释,声明路径操作函数中路径参数的类型。

from fastapi import FastAPIapp = FastAPI()@app.get("/items/{item_id}")
async def read_item(item_id: int):return {"item_id": item_id}

上例把item_id的类型声明为int

检查:类型声明将为函数提供错误检查、代码补全等编辑器支持

数据转换

运行上述声明item_id的类型为int的例子并访问 http://127.0.0.1:8000/items/3,返回的相应如下:

{"item_id":3}

可见,函数接收并返回的值是3int),不是"3"str)。FastAPI通过类型声明自动解析请求中的数据

数据校验

如果通过浏览器访问http://127.0.0.1:8000/items/foo,将会接收如下HTTP错误信息:

{"detail": [{"type": "int_parsing","loc": ["path","item_id"],"msg": "Input should be a valid integer, unable to parse string as an integer","input": "foo"}]
}

因为路径参数item_id的值("foo")的类型不是int

检查:FastAPI使用Python类型声明实现了数据校验,上面的错误清晰的指出了未通过校验的具体原因,这在开发调试与API交互的代码时非常有用。

查看文档

访问 http://127.0.0.1:8000/docs,查看自动生成的 API 文档:

Pydantic

FastAPI可以充分利用Pydanic的优势,用它在后台校验数据。

路径操作的顺序

from fastapi import FastAPIapp = FastAPI()@app.get("/users/me")
async def read_user_me():return {"user_id": "the current user"}@app.get("/users/{user_id}")
async def read_user(user_id: str):return {"user_id": user_id}

/users/me/users/{user_id}不能反过来,否则/users/me的路径会被/users/{user_id}接收。

预设值

路径操作使用Python的Enum类型接收预设的路径参数。

from enum import Enumfrom fastapi import FastAPIclass ModelName(str, Enum):alexnet = "alexnet"resnet = "resnet"lenet = "lenet"app = FastAPI()@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):if model_name is ModelName.alexnet:return {"model_name": model_name, "message": "Deep Learning FTW!"}if model_name.value == "lenet":return {"model_name": model_name, "message": "LeCNN all the images"}return {"model_name": model_name, "message": "Have some residuals"}
  • 导入Enum并创建继承自strEnum的子类。通过从str继承,API文档就能把值的类型定义为字符串,并且能正确渲染。然后创建包含固定值的类属性,这些固定值是可用的有效值。
  • 使用Enum类(ModelName)创建使用类型注解的路径参数。
  • API文档会显示预定义路径参数的可用值。
    在这里插入图片描述
  • 使用Python枚举类型:路径参数的值是枚举的元素。枚举类ModelName中的枚举元素支持比较操作(if model_name is ModelName.alexnet),使用model_name.value获取枚举值。
  • 返回枚举元素:即使嵌套在JSON请求体里(例如,dict),也可以从路径操作返回枚举元素。

包含路径的路径参数

from fastapi import FastAPIapp = FastAPI()@app.get("/files/{file_path:path}")
async def read_file(file_path: str):return {"file_path": file_path}

参数名为file_path,结尾部分的:path说明该参数应匹配路径。

查询参数

声明的参数不是路径参数时,路径操作函数会把该参数自动解释为查询参数

from fastapi import FastAPIapp = FastAPI()fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):return fake_items_db[skip : skip + limit]

查询字符串是键值对的集合,这些键值对位于URL的?之后,以&分隔。
例如,以下URL中:

http://127.0.0.1:8000/items/?skip=0&limit=2

查询参数为:skip: 0limit: 2
这些值都是URL的组成部分,因此它们的类型本应是字符串。
但声明Python类型(上例中为int)之后,这些值就会转换为声明的类型,并进行类型校验。
所有应用于路径参数的流程也适用于查询参数。

默认值

查询参数由默认值,如上例。
可以进行如下URL访问:

  • http://127.0.0.1:8000/items/
  • http://127.0.0.1:8000/items/?skip=0&limit=10
  • http://127.0.0.1:8000/items/?skip=20

可选参数

把默认值设为None即可声明可选的查询参数:

from fastapi import FastAPIapp = FastAPI()@app.get("/items/{item_id}")
async def read_item(item_id: str, q: str | None = None):if q:return {"item_id": item_id, "q": q}return {"item_id": item_id}

检查:注意,FastAPI 可以识别出 item_id 是路径参数,q 不是路径参数,而是查询参数。

查询参数类型转换

FastAPI会自动转换参数类型:

from typing import Unionfrom fastapi import FastAPIapp = FastAPI()@app.get("/items/{item_id}")
async def read_item(item_id: str, q: Union[str, None] = None, short: bool = False):item = {"item_id": item_id}if q:item.update({"q": q})if not short:item.update({"description": "This is an amazing item that has a long description"})return item

在本例中访问:

http://127.0.0.1:8000/items/foo?short=1

http://127.0.0.1:8000/items/foo?short=True

或short=on,short=true,short=yes或其它任意大小写形式,函数接收到的short参数都是布尔值TrueFalse同理(0,false,off,no)。

多个路径和查询参数

FastAPI可以识别同时声明的多个路径参数和查询参数,而且声明查询参数的顺序并不重要,FastAPI通过参数名进行检测:

from typing import Unionfrom fastapi import FastAPIapp = FastAPI()@app.get("/users/{user_id}/items/{item_id}")
async def read_user_item(user_id: int, item_id: str, q: Union[str, None] = None, short: bool = False
):item = {"item_id": item_id, "owner_id": user_id}if q:item.update({"q": q})if not short:item.update({"description": "This is an amazing item that has a long description"})return item

把不是路径参数的参数(至此只有查询参数)声明为默认值,或者是吧默认值设为None,这样参数就不是必选的,否则是必选的。

上述代码可以用以下URL进行测试:

http://127.0.0.1:8000/users/2/items/item_id?q=test&short=0

将会得到这样的相应:

{"item_id":"item_id","owner_id":2,"q":"test","description":"This is an amazing item that has a long description"}

再比如:

from typing import Unionfrom fastapi import FastAPIapp = FastAPI()@app.get("/items/{item_id}")
async def read_user_item(item_id: str, needy: str, skip: int = 0, limit: Union[int, None] = None
):item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit}return item

上例中有3个查询参数:needy,必选的str类型参数,skip,默认值为0int类型参数,limit,可选的int类型参数。

请求体

FastAPI使用请求体从客户端(例如浏览器)向API发送数据。

请求体是客户端发送给API的数据。响应体是API发送给客户端的数据。

API基本上肯定要发送响应体,但是客户端不一定发送请求体

使用Pydantic模型声明请求体,能充分利用它的功能和优点。

使用Pydantic声明请求体

from fastapi import FastAPI
from pydantic import BaseModelclass Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Noneapp = FastAPI()@app.post("/items/")
async def create_item(item: Item):return item

步骤如下:

  • pydantic中导入BaseModel
  • 创建数据类型:把数据模型声明为继承BaseModel的类。使用Python标准类型声明所有属性。
  • 声明请求体参数:使用与声明路径和查询参数相同的方式声明请求体,把请求体添加至路径操作,@app.post()及其下面的函数async def create_item(item: Item):...,此处请求体参数的类型为Item类型。

使用如下代码进行测试:

import requests# 定义请求的 JSON 数据
item_data = {"name": "Item1","description": "This is item 1","price": 19.99,"tax": 2.00
}# 发送 POST 请求
response = requests.post("http://localhost:8000/items/", json=item_data)# 打印返回的 JSON 数据
print(response.json())

可以看到,FastAPI接收来自测试代码的请求,返回:

{'name': 'Item1', 'description': 'This is item 1', 'price': 19.99, 'tax': 2.0}

结论

仅使用Python类型声明,FastAPI就可以

  • 以JSON形式读取请求体
  • (在必要时)把请求体转换为对应的类型
  • 校验数据:数据无效时返回错误信息,并指出错误数据的确切位置和内容
  • 把接收的数据赋值给参数item
  • 为模型生成JSON Schema,在项目中所需的位置使用

使用模型

在路径操作函数内部直接访问模型对象的属性:

from fastapi import FastAPI
from pydantic import BaseModelclass Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Noneapp = FastAPI()@app.post("/items/")
async def create_item(item: Item):item_dict = item.dict()if item.tax:price_with_tax = item.price + item.taxitem_dict.update({"price_with_tax": price_with_tax})return item_dict

用测试代码测试结果如下:

{'description': 'Mechanical keyboard','name': 'Keyboard','price': 49.99,'price_with_tax': 54.99,'tax': 5.0}

请求体+路径参数

FastAPI支持同时声明路径参数和请求体。

FastAPI能识别与路径参数匹配的函数参数,还能识别从请求体中获取的类型为Pydantic模型的函数参数。

from fastapi import FastAPI
from pydantic import BaseModelclass Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Noneapp = FastAPI()@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):return {"item_id": item_id, **item.dict()}

使用如下测试代码发送PUT请求:

import requests
from pprint import pprint# 定义要发送的 JSON 数据,符合 Item 模型的定义
item_data = {"name": "Mouse","description": "Wireless mouse","price": 19.99,"tax": 1.50
}# 定义要更新的 item_id
item_id = 1# 发送 PUT 请求
response = requests.put(f"http://localhost:8000/items/{item_id}", json=item_data)# 打印返回的 JSON 数据
pprint(response.json())

返回结果为:

{'description': 'Wireless mouse','item_id': 1,'name': 'Mouse','price': 19.99,'tax': 1.5}

请求体+路径参数+查询参数

FastAPI支持同时声明请求体路径参数查询参数

from fastapi import FastAPI
from pydantic import BaseModelclass Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Noneapp = FastAPI()@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, q: str | None = None):result = {"item_id": item_id, **item.dict()}if q:result.update({"q": q})return result

函数参数按如下规则进行识别:

  • 路径中声明了相同参数的参数,是路径参数
  • 类型是(int,float,str,bool等)单类型的参数,是查询参数
  • 类型是Pydantic模型的参数,是请求体

使用如下测试代码:

import requests
from pprint import pprint# 定义要发送的 JSON 数据,符合 Item 模型的定义
item_data = {"name": "Keyboard","description": "Mechanical keyboard","price": 49.99,"tax": 5.00
}# 定义要更新的 item_id
item_id = 1# 定义查询参数 q
q_param = "example"# 发送 PUT 请求
response = requests.put(f"http://localhost:8000/items/{item_id}?q={q_param}", json=item_data)# 打印返回的 JSON 数据
pprint(response.json())

可得到返回结果:

{'description': 'Mechanical keyboard','item_id': 1,'name': 'Keyboard','price': 49.99,'q': 'example','tax': 5.0}

查询参数和字符串校验

FastAPI允许你为参数声明额外的信息和校验。
以下面的应用程序为例:

from fastapi import FastAPIapp = FastAPI()@app.get("/items/")
async def read_items(q: str | None = None):results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}if q:results.update({"q": q})return results

查询参数q的类型为str,默认值为None,因此它是可选的。

额外的校验

我们打算添加约束条件:即使q是可选的,但只要提供了该参数,则该参数值不能超过50个字符的长度

具体步骤如下:

  • 导入Query:首先从fastapi导入Query
  • 使用Query作为默认值:将Query用作查询参数的默认值,并将它的max_length参数设置为50,由于我们必须用Query(default=None)替换默认值NoneQuery的第一个参数同样是用于定义默认值。
from typing import Unionfrom fastapi import FastAPI, Queryapp = FastAPI()@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, max_length=50)):results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}if q:results.update({"q": q})return results

添加更多的校验

  • 还可以添加min_length参数
  • 还可以添加正则表达式:定义一个参数值必须匹配的正则表达式
from typing import Unionfrom fastapi import FastAPI, Queryapp = FastAPI()@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, min_length=3, max_length=50, pattern="^fixedquery$"),
):results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}if q:results.update({"q": q})return results

声明为必需参数

当我们不需要声明额外的校验或元数据时,只需不声明默认值就可以使q参数成为必需参数,如:

q: str

但是我们现在正在用Query声明它,如:

q: Union[str, None] = Query(default=None, min_length=3)

因此,当你在使用Query且需要声明一个值是必需的时,只需不声明默认参数:

from fastapi import FastAPI, Queryapp = FastAPI()@app.get("/items/")
async def read_items(q: str = Query(min_length=3)):results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}if q:results.update({"q": q})return results

显式声明必需参数的方法

  • 使用(...)声明:q: str = Query(default=..., min_length=3)
  • 可以声明None为一个有效的类型,仍是必需参数:q: Union[str, None] = Query(default=..., min_length=3)
  • 使用Pydantic中的Required代替省略号...from pydantic import Requiredq: str = Query(default=Required, min_length=3)

大多数情况,隐式省略default参数就够了,通常不必使用显式声明...Required

查询参数列表/多个值

当你使用Query显式地定义查询参数时,你还可以声明它去接收一组值,或换句话来说,接收多个值。

例如,要声明一个可在URL中出现多次的查询参数q,可以这样写:

from typing import List, Unionfrom fastapi import FastAPI, Queryapp = FastAPI()@app.get("/items/")
async def read_items(q: Union[List[str], None] = Query(default=None)):query_items = {"q": q}return query_items

然后输入以下网址:

http://localhost:8000/items/?q=foo&q=bar

你会在路径操作函数的函数参数q中以一个Pythonlist的形式接收到查询参数q的多个值:

{"q":["foo","bar"]}

要声明类型为list的查询参数,需要显式地使用Query,否则该参数将被解释为请求体

具有默认值的查询参数列表/多个值

可以给定默认list值:

from typing import Listfrom fastapi import FastAPI, Queryapp = FastAPI()@app.get("/items/")
async def read_items(q: List[str] = Query(default=["foo", "bar"])):query_items = {"q": q}return query_items

q: List[str] = Query(default=["foo", "bar"])也可以使用list代替,这样不会检查列表的内容,如q: list = Query(default=[])

声明更多元数据

你可以添加更多有关该参数的信息。
这些信息将包含在生成的OpenAPI模式中,并由文档用户界面和外部工具所使用。

  • 添加title
from typing import Unionfrom fastapi import FastAPI, Queryapp = FastAPI()@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, title="Query string", min_length=3),
):results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}if q:results.update({"q": q})return results
  • 添加description
from typing import Unionfrom fastapi import FastAPI, Queryapp = FastAPI()@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None,title="Query string",description="Query string for the items to search in the database that have a good match",min_length=3,),
):results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}if q:results.update({"q": q})return results

别名参数(alias)

假设你想要查询参数为item-query,如下:

http://127.0.0.1:8000/items/?item-query=foobaritems

但是item-query不是一个有效的Python变量名称,这时可以用alias参数声明一个别名,该别名将用于在URL中查找查询参数值:

from typing import Unionfrom fastapi import FastAPI, Queryapp = FastAPI()@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None, alias="item-query")):results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}if q:results.update({"q": q})return results

弃用参数(deprecated)

假设你不再喜欢该参数。

你不得不将其保留一段时间,因为有些客户端正在使用它,但你希望文档清楚地将其展示为已弃用

那么将deprecated=True传入Query

from typing import Unionfrom fastapi import FastAPI, Queryapp = FastAPI()@app.get("/items/")
async def read_items(q: Union[str, None] = Query(default=None,alias="item-query",title="Query string",description="Query string for the items to search in the database that have a good match",min_length=3,max_length=50,pattern="^fixedquery$",deprecated=True,),
):results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}if q:results.update({"q": q})return results

文档会像下面这样展示它:
在这里插入图片描述

总结

你可以为查询参数声明额外的校验和元数据。
通用的校验和元数据:

  • alias
  • title
  • description
  • deprecated

特定于字符串的校验:

  • min_length
  • max_length
  • regex

路径参数和数值校验

与使用Query为查询参数声明更多的校验和元数据的方式相同,你也可以使用Path为路径参数声明相同类型的校验和元数据。

具体步骤如下:

  • 导入Path:首先从fastapi导入Path
  • 声明元数据:可以声明与Query相同的所有参数,例如,要声明路径参数item_idtitle元数据值,可以输入item_id: Annotated[int, Path(title="The ID of the item to get")]
from typing import Annotatedfrom fastapi import FastAPI, Path, Queryapp = FastAPI()@app.get("/items/{item_id}")
async def read_items(item_id: Annotated[int, Path(title="The ID of the item to get")],q: Annotated[str | None, Query(alias="item-query")] = None,
):results = {"item_id": item_id}if q:results.update({"q": q})return results

路径参数总是必需的

按需对参数排序

假设你想要声明一个必需的str类型查询参数q
而且你不需要为该参数声明任何其他内容,所以实际上并不需要使用Query
但是你仍然需要使用Path来声明路径参数item_id
如果你将带有【默认值】的参数放在没有【默认值】的参数之前,Python将会报错。
但是你可以对其重新排序,并将不带默认值的值(查询参数q)放到最前面。
对FastAPI来说这无关紧要。它将通过参数的名称、类型和默认值声明(QueryPath等)来检测参数,而不在乎参数的顺序。

因此可以将函数声明为:

from fastapi import FastAPI, Pathapp = FastAPI()@app.get("/items/{item_id}")
async def read_items(q: str, item_id: int = Path(title="The ID of the item to get")):results = {"item_id": item_id}if q:results.update({"q": q})return results

还可以用*表示后面的所有参数作为关键字参数,也被称为kwargs来调用,即使它们没有默认值

from fastapi import FastAPI, Pathapp = FastAPI()@app.get("/items/{item_id}")
async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):results = {"item_id": item_id}if q:results.update({"q": q})return results

数值校验

使用QueryPath(以及后面的其他类)可以声明字符串约束,也可以声明数值约束。如下,添加ge=1后,item_id将必须是一个大于(greater than)或等于(equal1的整数。

  • 大于等于
from fastapi import FastAPI, Pathapp = FastAPI()@app.get("/items/{item_id}")
async def read_items(*, item_id: int = Path(title="The ID of the item to get", ge=1), q: str
):results = {"item_id": item_id}if q:results.update({"q": q})return results
  • 大于:gt(greater than)
  • 小于等于:le(less than or equal)
from fastapi import FastAPI, Pathapp = FastAPI()@app.get("/items/{item_id}")
async def read_items(*,item_id: int = Path(title="The ID of the item to get", gt=0, le=1000),q: str,
):results = {"item_id": item_id}if q:results.update({"q": q})return results
  • 浮点数:数值校验同样适用于float值。

请求体-多个参数

既然我们已经知道了如何使用PathQuery,下面让我们来了解一下请求体声明的更高级用法。

混合使用PathQuery和请求体参数

你可以随意混合使用PathQuery和请求体参数声明。
你还可以通过将默认值设置为None来将请求体参数声明为可选参数:

from typing import Annotatedfrom fastapi import FastAPI, Path
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = None@app.put("/items/{item_id}")
async def update_item(item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],q: str | None = None,item: Item | None = None,
):results = {"item_id": item_id}if q:results.update({"q": q})if item:results.update({"item": item})return results

多个请求体参数

from fastapi import FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Noneclass User(BaseModel):username: strfull_name: str | None = None@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, user: User):results = {"item_id": item_id, "item": item, "user": user}return results

在上面的情况下,FastAPI将注意到该函数中有多个请求体参数(两个Pydantic模型参数)。因此,它将使用参数名称作为请求体中的键(字段名称),并期望一个类似于以下内容的请求体:

{"item": {"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2},"user": {"username": "dave","full_name": "Dave Grohl"}
}

FastAPI将自动对请求中的数据进行转换,因此item参数将接收指定的内容,user参数也是如此。它将执行对复合数据的校验,并且像现在这样为OpenAPI模式和自动化文档对其进行记录。

请求体中的单一值(Body)

与使用QueryPath为查询参数和路径参数定义额外数据的方式相同,FastAPI提供了一个同等的Body,例如上面的模型,除了itemuser之外,还想在同一请求体中具有另一个键importance,如果按原样来声明它,因为它是一个单一值,FastAPI将假定它是一个查询参数。但是你可以使用Body指示FastAPI将其作为请求体的另一个键进行处理。

from typing import Annotatedfrom fastapi import Body, FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Noneclass User(BaseModel):username: strfull_name: str | None = None@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, user: User, importance: Annotated[int, Body()]
):results = {"item_id": item_id, "item": item, "user": user, "importance": importance}return results

在这种情况下,FastAPI将期望这样的请求体:

{"item": {"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2},"user": {"username": "dave","full_name": "Dave Grohl"},"importance": 5
}

多个请求体参数和查询参数

除了请求体参数外,你还可以在任何需要的时候声明额外的查询参数。
由于默认情况下单一值被解释为查询参数,因此你不必显式地添加Query

from typing import Annotatedfrom fastapi import Body, FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Noneclass User(BaseModel):username: strfull_name: str | None = None@app.put("/items/{item_id}")
async def update_item(*,item_id: int,item: Item,user: User,importance: Annotated[int, Body(gt=0)],q: str | None = None,
):results = {"item_id": item_id, "item": item, "user": user, "importance": importance}if q:results.update({"q": q})return results

嵌入单个请求体参数(Body(embed=True))

假设你只有一个来自Pydantic模型Item的请求体参数item
默认情况下,FastAPI将直接期望这样的请求体。
但是,如果你希望它期望一个拥有item键并在值中包含模型内容的JSON,就像在声明额外的请求体参数时所做的那样,则可以使用一个特殊的Body参数embed

item: Item = Body(embed=True)
from typing import Annotatedfrom fastapi import Body, FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = None@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):results = {"item_id": item_id, "item": item}return results

在这种情况下,FastAPI将期望像这样的请求体:

{"item": {"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2}
}

而不是:

{"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2
}

总结

你可以添加多个请求体参数到路径操作函数中,即使一个请求只能有一个请求体。

但是 FastAPI 会处理它,在函数中为你提供正确的数据,并在路径操作中校验并记录正确的模式。

你还可以声明将作为请求体的一部分所接收的单一值。

你还可以指示 FastAPI 在仅声明了一个请求体参数的情况下,将原本的请求体嵌入到一个键中。

请求体-字段(Field)

与在路径操作函数中使用QueryPathBody声明校验与元数据的方式一样,可以使用Pydantic的Field在Pydantic模型内部声明校验和元数据。

具体步骤如下:

  • 导入Field:首先从Pydantic中导入Field
  • 声明模型属性:使用Field定义模型的属性。
from typing import Annotatedfrom fastapi import Body, FastAPI
from pydantic import BaseModel, Fieldapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Field(default=None, title="The description of the item", max_length=300)price: float = Field(gt=0, description="The price must be greater than zero")tax: float | None = None@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):results = {"item_id": item_id, "item": item}return results

Field的工作方式和QueryPathBody相同,参数也相同。

请求体-嵌套类型

使用FastAPI,你可以定义、校验、记录文档并使用任意深度嵌套的模型(归功于Pydantic)。

List字段

你可以将一个属性定义为拥有子元素的类型。例如Pythonlist

from fastapi import FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Nonetags: list = []@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):results = {"item_id": item_id, "item": item}return results

这将使tags成为一个由元素组成的列表。不过它没有声明每个元素的类型。

具有子类型的List字段

但是Python有一种特定的方法来声明具有子类型的列表:

具体步骤如下:

  • 声明具有子类型的List:从typing模块导入它们,使用方括号[]将子类型作为【类型参数】传入。
  • 在我们的示例中,我们可以将tags明确地指定为一个【字符串列表】。
from fastapi import FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Nonetags: list[str] = []@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):results = {"item_id": item_id, "item": item}return results

Set类型

标签不应该重复,所以用Settag声明为一个由str组成的set

from fastapi import FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Nonetags: set[str] = set()@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):results = {"item_id": item_id, "item": item}return results

这样,即使收到带有重复数据的请求,这些数据也会被转换为一组唯一项。

而且,每当你输出该数据时,即使源数据有重复,它们也将作为一组唯一项输出。

并且还会被相应地标注/记录文档。

嵌套类型

Pydantic模型的每个属性都具有类型。但是这个类型本身可以是另一个Pydantic模型。因此,你可以声明拥有特定属性名称、类型和校验的深度嵌套的JSON对象。

例如:

  • 定义一个Image模型
  • Image模型用作一个属性的类型
from fastapi import FastAPI
from pydantic import BaseModelapp = FastAPI()class Image(BaseModel):url: strname: strclass Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Nonetags: set[str] = set()image: Image | None = None@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):results = {"item_id": item_id, "item": item}return results

这意味着FastAPI将期望类似于以下内容的请求体:

{"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2,"tags": ["rock", "metal", "bar"],"image": {"url": "http://example.com/baz.jpg","name": "The Foo live"}
}

特殊的类型和校验

除了普通的单一值类型(如strintfloat等)外,你还可以使用从str继承的更复杂的单一值类型。

要了解所有的可用选项,查看来自Pydantic的外部类型的文档。

例如,在Image模型中我们有一个url字段,我们可以把它声明为Pydantic的HttpUrl,而不是str

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrlapp = FastAPI()class Image(BaseModel):url: HttpUrlname: strclass Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Nonetags: set[str] = set()image: Image | None = None@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):results = {"item_id": item_id, "item": item}return results

该字符串将被检查是否为有效的URL,并在JSON Schema/OpenAPI文档中进行记录。

带有一组子模型的属性

你还可以将Pydantic模型用作listset等的子模型:

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrlapp = FastAPI()class Image(BaseModel):url: HttpUrlname: strclass Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Nonetags: set[str] = set()images: list[Image] | None = None@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):results = {"item_id": item_id, "item": item}return results

这将期望(转换,校验,记录文档等)下面这样的JSON请求体:

{"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2,"tags": ["rock","metal","bar"],"images": [{"url": "http://example.com/baz.jpg","name": "The Foo live"},{"url": "http://example.com/dave.jpg","name": "The Baz"}]
}

深度嵌套模型

你可以定义任意深度的嵌套模型:

from typing import Unionfrom fastapi import FastAPI
from pydantic import BaseModel, HttpUrlapp = FastAPI()class Image(BaseModel):url: HttpUrlname: strclass Item(BaseModel):name: strdescription: Union[str, None] = Noneprice: floattax: Union[float, None] = Nonetags: set[str] = set()images: Union[list[Image], None] = Noneclass Offer(BaseModel):name: strdescription: Union[str, None] = Noneprice: floatitems: list[Item]@app.post("/offers/")
async def create_offer(offer: Offer):return offer

纯列表请求体

如果你期望的JSON请求体的最外层是一个JSONarray(即Python list),则可以在路径操作函数的参数中声明此类型,就像声明Pydantic模型一样:

images: List[Image]

例如:

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrlapp = FastAPI()class Image(BaseModel):url: HttpUrlname: str@app.post("/images/multiple/")
async def create_multiple_images(images: list[Image]):return images

任意dict构成的请求体

你也可以将请求体声明为使用某类型的键和其他类型值的dict
无需事先知道有效的字段/属性(在使用Pydantic模型的场景)名称是什么。
如果你想接收一些尚且未知的键,这将很有用。

其他有用的场景是当你想要接收其他类型的键时,例如int,如下,你将接受任意键为int类型并且值为float类型的dict

from fastapi import FastAPIapp = FastAPI()@app.post("/index-weights/")
async def create_index_weights(weights: dict[int, float]):return weights

JSON仅支持将str作为键,但是Pydantic具有自动转换数据的功能。这意味着,即使你的API客户端只能将字符串作为键发送,只要这些字符串内容仅包含整数,Pydantic就会对其进行转换并校验。然后你接收的名为weightsdict实际上将具有int类型的键和float类型的值。

模式的额外信息-例子

你可以在JSON模式中定义额外的信息。
一个常见的用例是添加一个将在文档中显示的example
有几种方法可以声明额外的JSON模式信息。

Pydantic schema_extra

你可以使用Configschema_extra为Pydantic模型声明一个示例,如Pydantic文档:定制Schema中所述。

from fastapi import FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = Nonemodel_config = {"json_schema_extra": {"examples": [{"name": "Foo","description": "A very nice Item","price": 35.4,"tax": 3.2,}]}}@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):results = {"item_id": item_id, "item": item}return results

这些额外的信息将按原样添加到输出的JSON模式中。

Field的附加参数

FieldPathQueryBody和其他你之后将会看到的工厂函数,你可以为JSON模式声明额外信息,你也可以通过给工厂函数传递其他的任意参数来给JSON模式声明额外信息,比如增加example

from fastapi import FastAPI
from pydantic import BaseModel, Fieldapp = FastAPI()class Item(BaseModel):name: str = Field(examples=["Foo"])description: str | None = Field(default=None, examples=["A very nice Item"])price: float = Field(examples=[35.4])tax: float | None = Field(default=None, examples=[3.2])@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):results = {"item_id": item_id, "item": item}return results

传递的那些额外参数不会添加任何验证,只会添加注释,用于文档的目的。

Body额外参数

from typing import Annotatedfrom fastapi import Body, FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: str | None = Noneprice: floattax: float | None = None@app.put("/items/{item_id}")
async def update_item(item_id: int,item: Annotated[Item,Body(examples=[{"name": "Foo","description": "A very nice Item","price": 35.4,"tax": 3.2,}],),],
):results = {"item_id": item_id, "item": item}return results

额外数据类型

到目前为止,一直在使用常见的数据类型,如:

  • int
  • float
  • str
  • bool
    但是也可以使用更复杂的数据类型。

其他数据类型

  • UUID:
    一种标准的 “通用唯一标识符” ,在许多数据库和系统中用作ID。
    在请求和响应中将以 str 表示。
  • datetime.datetime:
    一个 Python datetime.datetime.
    在请求和响应中将表示为 ISO 8601 格式的 str ,比如: 2008-09-15T15:53:00+05:00.
  • datetime.date:
    Python datetime.date.
    在请求和响应中将表示为 ISO 8601 格式的 str ,比如: 2008-09-15.
  • datetime.time:
    一个 Python datetime.time.
    在请求和响应中将表示为 ISO 8601 格式的 str ,比如: 14:23:55.003.
  • datetime.timedelta:
    一个 Python datetime.timedelta.
    在请求和响应中将表示为 float 代表总秒数。
    Pydantic 也允许将其表示为 “ISO 8601 时间差异编码”, 查看文档了解更多信息。
  • frozenset:
    在请求和响应中,作为 set 对待:
    在请求中,列表将被读取,消除重复,并将其转换为一个 set
    在响应中 set 将被转换为 list
    产生的模式将指定那些 set 的值是唯一的 (使用 JSON 模式的 uniqueItems)。
  • bytes:
    标准的 Python bytes
    在请求和响应中被当作 str 处理。
    生成的模式将指定这个 strbinary “格式”。
  • Decimal:
    标准的 Python Decimal
    在请求和响应中被当做 float 一样处理。
    您可以在这里检查所有有效的pydantic数据类型: Pydantic data types.

例子

from datetime import datetime, time, timedelta
from typing import Annotated
from uuid import UUIDfrom fastapi import Body, FastAPIapp = FastAPI()@app.put("/items/{item_id}")
async def read_items(item_id: UUID,start_datetime: Annotated[datetime, Body()],end_datetime: Annotated[datetime, Body()],process_after: Annotated[timedelta, Body()],repeat_at: Annotated[time | None, Body()] = None,
):start_process = start_datetime + process_afterduration = end_datetime - start_processreturn {"item_id": item_id,"start_datetime": start_datetime,"end_datetime": end_datetime,"process_after": process_after,"repeat_at": repeat_at,"start_process": start_process,"duration": duration,}

相关文章:

FastAPI教程I

本文参考FastAPI教程https://fastapi.tiangolo.com/zh/tutorial 第一步 import uvicorn from fastapi import FastAPIapp FastAPI()app.get("/") async def root():return {"message": "Hello World"}if __name__ __main__:uvicorn.run(&quo…...

如何在 HTML 中实现响应式设计以适应不同设备的屏幕尺寸?

要在HTML中实现响应式设计以适应不同设备的屏幕尺寸,可以使用CSS媒体查询和流动布局。 以下是实现响应式设计的一些关键步骤: 使用CSS媒体查询:CSS媒体查询允许根据屏幕尺寸和设备特性应用不同的CSS样式。通过在CSS中使用media规则&#xf…...

【基础篇】第1章 Elasticsearch 引言

1.1 Elasticsearch简介 1.1.1 基本概念 Elasticsearch,一个开源的分布式搜索引擎,以其强大的搜索能力和实时数据分析能力,在大数据时代脱颖而出。它基于Apache Lucene库构建,旨在提供高效、可扩展且易于使用的全文检索解决方案。…...

在区块链技术广泛应用的情况下,C 语言如何在区块链的底层开发中发挥更有效的作用,提高性能和安全性?

C语言在区块链底层开发中发挥着重要的作用,可以提高性能和安全性。具体可以从以下几个方面进行优化: 性能优化:C语言是一种高效的编程语言,可以直接访问内存和硬件资源。在区块链底层开发中,使用C语言可以更好地利用底…...

量化投资 日周月报 2024-06-28

文章 深度学习在量化交易中的应用:在BigQuant量化交易平台的文章中,探讨了深度学习在量化交易中,特别是在因子挖掘方面的应用。文章提到,随着传统线性模型的潜力逐渐枯竭,非线性模型逐渐成为量化交易的主要探索方向。深度学习因其对非线性关系的拟合能力,在量化交易中展现…...

基于 Paimon 的袋鼠云实时湖仓入湖实战剖析

在当今数据驱动的时代,企业对数据的实施性能力提出了前所未有的高要求。为了应对这一挑战,构建高效、灵活且可扩展的实时湖仓成为数字化转型的关键。本文将深入探讨袋鼠云数栈如何通过三大核心实践——ChunJun 融合 Flink CDC、MySQL 一键入湖至 Paimon …...

IPython相关了解

一、什么是 IPython? 1.1 简单理解 IPython IPython 是一种增强的 Python 交互式解释器,它可以让你更方便地编写、调试和运行 Python 代码。你可以把它想象成一个比普通 Python 解释器更聪明、功能更丰富的工具,非常适合用来进行数据探索、…...

华为面试题及答案——机器学习(二)

21. 如何评价分类模型的优劣? (1)模型性能指标 准确率(Accuracy): 定义:正确分类的样本数与总样本数之比。适用:当各类样本的数量相对均衡时。精确率(Precision): 定义:预测为正类的样本中实际为正类的比例。适用:当关注假阳性错误的成本较高时(例如垃圾邮件检测…...

PlatformIO开发环境

PlatformIO是一个开源的生态系统,用于构建物联网应用,它支持多种微控制器(MCU)和硬件开发板,并且与各种IDE集成良好,如VSCode, Atom等,使得跨平台的固件开发变得更加简单和高效。 ### 平台介绍…...

In install.packages(“devtools“, verbose = TRUE) :

错误于curl::curl_download("https://r-lib.github.io/gert/libgit2-1.1.0.x86_64_legacy-linux.tar.gz", : Timeout was reached: [] Connection timed out after 10004 milliseconds 停止执行 Using PKG_CFLAGS Using PKG_LIBS-lgit2 ----------------------------…...

计算机网络 访问控制列表以及NAT

一、理论知识 1. 单臂路由 单臂路由是一种在路由器上配置多个子接口的方法,每个子接口代表不同的 VLAN,用于在一个物理接口上支持多 VLAN 通信。此方法使得不同 VLAN 之间可以通过路由器进行通信。 2. NAT (网络地址转换) NAT 是一种在私有网络和公共…...

使用Oracle IMP导入数据

使用Oracle IMP导入数据 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们来聊一聊如何使用Oracle的IMP工具来导入数据。 一、什么是Oracle IMP Oracle…...

C++ 100 之 容器插入和删除

vector插入和删除操作 insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele. push_back(ele); //尾部插入元素ele pop_back();//删除最后一个元素 erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素 erase(c…...

提升 Selenium 测试稳定性的秘诀:深入理解等待 API 的使用

目录 为什么需要等待Selenium 等待 API 简介隐式等待显式等待Fluent Wait等待策略的选择示例代码总结 正文 1. 为什么需要等待 在 Web 自动化测试中,等待是一个关键因素。网络应用通常是动态的,页面加载时间、元素的显示时间都可能不同步。直接操作这…...

Python-算法编程100例-滑动窗口(入门级)

题目1:最大连续1的个数(简单) 给定一个二进制数组 nums , 计算其中最大连续 1 的个数。 解答:前缀和双指针 # 给定一个二进制数组 nums , 计算其中最大连续 1 的个数。 from typing import Listclass So…...

ffmpeg使用mjpeg把yuvj420p编码为jpg图像

version #define LIBAVUTIL_VERSION_MAJOR 58 #define LIBAVUTIL_VERSION_MINOR 12 #define LIBAVUTIL_VERSION_MICRO 100 node 不使用AVOutputFormat code void CFfmpegOps::EncodeYUVJ420pToMJPEG(const char* infile, const char* width_str, const char* height_s…...

龙迅#LT6911GXC支持HDMI2.1转MIPI/4PORT LVDS应用功能,分辨率高达8K30HZ/4K120HZ压缩格式。

1. 描述 该LT6911GXC是一款高性能HD-DVI2.1转MIPI或LVDS芯片,适用于VR/显示应用。 HDCP RX作为HDCP中继器的上游,可以与其他芯片的HDCP TX配合实现中继器功能。 对于 HD-DVI2.1 输入,LT6911GXC可以配置为 3/4 通道。 对于MIPI输出&#xff0c…...

.NET 6.0 Web API项目中实现基于Token的身份验证

本文以一个完整的示例,展示如何在.NET 6.0 Web API项目中实现基于Token的身份验证。这个例子包括了如何创建和验证JWT Token,以及如何在控制器中使用这些Token。 步骤 1: 创建Web API项目 首先,用Visual Studio 2022创建一个基于.NET6.0的 …...

Java常用对象的快速初始化

在Java中,有多种方式来快速初始化各种常用对象,如字符串数组(String[]),集合列表(List),映射表(Map),以及集合(Set)。不同…...

逻辑回归模型模拟实现:从零开始

引言 逻辑回归是一种用于二分类问题的机器学习算法。尽管它的名字中有“回归”,但它实际上是用于分类的。在本文中,我们将通过模拟数据来演示逻辑回归模型的实现。 逻辑回归简介 逻辑回归通过使用逻辑函数(通常是Sigmoid函数)将…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理&#xff1a…...

OpenLayers 可视化之热力图

注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...

零基础设计模式——行为型模式 - 责任链模式

第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...