typing是Python標準庫,用來做類型提示。FastAPI使用typing做了:
-
編輯器支持;
-
類型檢查;
-
定義類型,request path parameters, query parameters, headers, bodies, dependencies等等;
-
類型轉換;
-
數據驗證,並且在驗證失敗時自動生成錯誤;
-
OpenAPI文檔,自動生成接口參數;
編輯器支持typing
先看個簡單的例子:
def 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
也就是把首字母轉換成大寫後,用空格拼接起來。
假如在寫程序時,你並不知道這個轉換大寫的函數名是title
,那麼你會輸入.
之後查看:
結果根據沒有提示。
添加typing類型提示:
def 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"))
再試一把:
有了。
再比如:
def get_name_with_age(name: str, age: int):
name_with_age = name + " is this old: " + age
return name_with_age
因爲明確了類型,編輯器會做類型檢查。
聲明類型
簡單類型:
int
float
bool
bytes
def 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_d, item_e
List
Python不同版本對typing的支持是不一樣的,3.6以上版本:
from typing import List
def process_items(items: List[str]):
for item in items:
print(item)
而3.9以上版本:
def process_items(items: list[str]):
for item in items:
print(item)
不需要import typing,小寫的list就行,跟常規用法一致。
這樣編輯器就能提供支持:
Tuple和Set
3.9以上版本:
def process_items(items_t: tuple[int, int, str], items_s: set[bytes]):
return items_t, items_s
Dict
3.9以上版本:
def process_items(prices: dict[str, float]):
for item_name, item_price in prices.items():
print(item_name)
print(item_price)
Union
多種類型,比如int或str。
3.6以上版本:
from typing import Union
def process_item(item: Union[int, str]):
print(item)
3.10以上版本:
def process_item(item: int | str):
print(item)
不需要import,使用|
就可以了。
None
可能爲None。
3.6以上版本:
from typing import Optional
def say_hi(name: Optional[str] = None):
if name is not None:
print(f"Hey {name}!")
else:
print("Hello World")
from typing import Union
def say_hi(name: Union[str, None] = None):
if name is not None:
print(f"Hey {name}!")
else:
print("Hello World")
3.10以上版本:
def say_hi(name: str | None = None):
if name is not None:
print(f"Hey {name}!")
else:
print("Hello World")
Classes
把某個類作爲類型提示:
class Person:
def __init__(self, name: str):
self.name = name
def get_person_name(one_person: Person):
return one_person.name
也能得到編輯器支持:
Pydantic模型
Pydantic模型有點類似於Java的POJO,就是定義一個類,裏面有一堆屬性,這些屬性都有類型。在實例化的時候,會做類型檢查或類型轉換。
from datetime import datetime
from pydantic import BaseModel
class User(BaseModel):
id: int
name = "John Doe"
signup_ts: datetime | None = None
friends: list[int] = []
external_data = {
"id": "123",
"signup_ts": "2017-06-01 12:22",
"friends": [1, "2", b"3"],
}
user = User(**external_data)
print(user)
# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
print(user.id)
# > 123
注意,類型提示使用的是:
,初始化賦值使用的是=
。
Pydantic對於可選類型有個特殊語法...
,表示可以爲None,但是必填:
from pydantic import BaseModel, Field, ValidationError
class Model(BaseModel):
a: int | None
b: int | None = ...
c: int | None = Field(...)
print(Model(b=1, c=2))
#> a=None b=1 c=2
try:
Model(a=1, b=2)
except ValidationError as e:
print(e)
"""
1 validation error for Model
c
field required (type=value_error.missing)
"""
-
a、b、c都能接受None,比如
Model(a=None, b=None, c=None)
; -
a可選,比如
Model(b=1, c=2)
是ok的; -
b和c都是必填,比如
Model(a=1, b=2)
會報錯;
Python版本
從示例代碼來看,Python3.10版本提供了更簡潔的語法,能讓代碼看起來更優雅。而且Python3.10版本也引入了switch語句,如果沒有什麼歷史原因,推薦大家使用Python3.10版本。
參考資料:
Python Types Intro - FastAPI https://fastapi.tiangolo.com/python-types/