Python 類型提示簡介

2022-08-20 11:29 更新

Python 3.6+ 版本加入了對"類型提示"的支持。

這些"類型提示"是一種新的語法(在 Python 3.6 版本加入)用來聲明一個變量的類型。

通過聲明變量的類型,編輯器和一些工具能給你提供更好的支持。

這只是一個關(guān)于 Python 類型提示的快速入門 / 復(fù)習(xí)。它僅涵蓋與 FastAPI 一起使用所需的最少部分...實際上只有很少一點。

整個 FastAPI 都基于這些類型提示構(gòu)建,它們帶來了許多優(yōu)點和好處。

但即使你不會用到 FastAPI,了解一下類型提示也會讓你從中受益。

Note

如果你已經(jīng)精通 Python,并且了解關(guān)于類型提示的一切知識,直接跳到下一章節(jié)吧。

動機(jī)

讓我們從一個簡單的例子開始:

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"))

運行這段程序?qū)⑤敵觯?/p>

John Doe

這個函數(shù)做了下面這些事情:

  • 接收 first_name 和 last_name 參數(shù)。
  • 通過 title() 將每個參數(shù)的第一個字母轉(zhuǎn)換為大寫形式。
  • 中間用一個空格來拼接它們。
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"))

修改示例

這是一個非常簡單的程序。

現(xiàn)在假設(shè)你將從頭開始編寫這段程序。

在某一時刻,你開始定義函數(shù),并且準(zhǔn)備好了參數(shù)...。

現(xiàn)在你需要調(diào)用一個"將第一個字母轉(zhuǎn)換為大寫形式的方法"。

等等,那個方法是什么來著?upper?還是 uppercase?first_uppercase?capitalize?

然后你嘗試向程序員老手的朋友——編輯器自動補全尋求幫助。

輸入函數(shù)的第一個參數(shù) first_name,輸入點號(.)然后敲下 Ctrl+Space 來觸發(fā)代碼補全。

但遺憾的是并沒有起什么作用:

添加類型

讓我們來修改上面例子的一行代碼。

我們將把下面這段代碼中的函數(shù)參數(shù)從:

    first_name, last_name

改成:

    first_name: str, last_name: str

就是這樣。

這些就是"類型提示":

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"))

這和聲明默認(rèn)值是不同的,例如:

    first_name="john", last_name="doe"

這兩者不一樣。

我們用的是冒號(:),不是等號(=)。

而且添加類型提示一般不會改變原來的運行結(jié)果。

現(xiàn)在假設(shè)我們又一次正在創(chuàng)建這個函數(shù),這次添加了類型提示。

在同樣的地方,通過 Ctrl+Space 觸發(fā)自動補全,你會發(fā)現(xiàn):

這樣,你可以滾動查看選項,直到你找到看起來眼熟的那個:

更多動機(jī)

下面是一個已經(jīng)有類型提示的函數(shù):

def get_name_with_age(name: str, age: int):
    name_with_age = name + " is this old: " + age
    return name_with_age

因為編輯器已經(jīng)知道了這些變量的類型,所以不僅能對代碼進(jìn)行補全,還能檢查其中的錯誤:

現(xiàn)在你知道了必須先修復(fù)這個問題,通過 str(age) 把 age 轉(zhuǎn)換成字符串:

def get_name_with_age(name: str, age: int):
    name_with_age = name + " is this old: " + str(age)
    return name_with_age

聲明類型

你剛剛看到的就是聲明類型提示的主要場景。用于函數(shù)的參數(shù)。

這也是你將在 FastAPI 中使用它們的主要場景。

簡單類型

不只是 str,你能夠聲明所有的標(biāo)準(zhǔn) Python 類型。

比如以下類型:

  • 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

嵌套類型

有些容器數(shù)據(jù)結(jié)構(gòu)可以包含其他的值,比如 dict、list、set 和 tuple。它們內(nèi)部的值也會擁有自己的類型。

你可以使用 Python 的 typing 標(biāo)準(zhǔn)庫來聲明這些類型以及子類型。

它專門用來支持這些類型提示。

列表

例如,讓我們來定義一個由 str 組成的 list 變量。

從 typing 模塊導(dǎo)入 List(注意是大寫的 L):

from typing import List


def process_items(items: List[str]):
    for item in items:
        print(item)

同樣以冒號(:)來聲明這個變量。

輸入 List 作為類型。

由于列表是帶有"子類型"的類型,所以我們把子類型放在方括號中:

from typing import List


def process_items(items: List[str]):
    for item in items:
        print(item)

這表示:"變量 items 是一個 list,并且這個列表里的每一個元素都是 str"。

這樣,即使在處理列表中的元素時,你的編輯器也可以提供支持。

沒有類型,幾乎是不可能實現(xiàn)下面這樣:

注意,變量 item 是列表 items 中的元素之一。

而且,編輯器仍然知道它是一個 str,并為此提供了支持。

元組和集合

聲明 tuple 和 set 的方法也是一樣的:

from typing import Set, Tuple


def process_items(items_t: Tuple[int, int, str], items_s: Set[bytes]):
    return items_t, items_s

這表示:

  • 變量 items_t 是一個 tuple,其中的每個元素都是 int 類型。
  • 變量 items_s 是一個 set,其中的每個元素都是 bytes 類型。

字典

定義 dict 時,需要傳入兩個子類型,用逗號進(jìn)行分隔。

第一個子類型聲明 dict 的所有鍵。

第二個子類型聲明 dict 的所有值:

from typing import Dict


def process_items(prices: Dict[str, float]):
    for item_name, item_price in prices.items():
        print(item_name)
        print(item_price)

這表示:

  • 變量 prices 是一個 dict:這個 dict 的所有鍵為 str 類型(可以看作是字典內(nèi)每個元素的名稱)。這個 dict 的所有值為 float 類型(可以看作是字典內(nèi)每個元素的價格)。

類作為類型

你也可以將類聲明為變量的類型。

假設(shè)你有一個名為 Person 的類,擁有 name 屬性:

class Person:
    def __init__(self, name: str):
        self.name = name


def get_person_name(one_person: Person):
    return one_person.name

接下來,你可以將一個變量聲明為 Person 類型:

class Person:
    def __init__(self, name: str):
        self.name = name


def get_person_name(one_person: Person):
    return one_person.name

然后,你將再次獲得所有的編輯器支持:

Pydantic 模型

Pydantic 是一個用來用來執(zhí)行數(shù)據(jù)校驗的 Python 庫。

你可以將數(shù)據(jù)的"結(jié)構(gòu)"聲明為具有屬性的類。

每個屬性都擁有類型。

接著你用一些值來創(chuàng)建這個類的實例,這些值會被校驗,并被轉(zhuǎn)換為適當(dāng)?shù)念愋停ㄔ谛枰那闆r下),返回一個包含所有數(shù)據(jù)的對象。

然后,你將獲得這個對象的所有編輯器支持。

下面的例子來自 Pydantic 官方文檔:

class Person:
    def __init__(self, name: str):
        self.name = name


def get_person_name(one_person: Person):
    return one_person.name

Info

想進(jìn)一步了解 Pydantic,請閱讀其文檔.

整個 FastAPI 建立在 Pydantic 的基礎(chǔ)之上。

實際上你將在 教程 - 用戶指南 看到很多這種情況。

FastAPI 中的類型提示

FastAPI 利用這些類型提示來做下面幾件事。

使用 FastAPI 時用類型提示聲明參數(shù)可以獲得:

  • 編輯器支持。
  • 類型檢查。

...并且 FastAPI 還會用這些類型聲明來:

  • 定義參數(shù)要求:聲明對請求路徑參數(shù)、查詢參數(shù)、請求頭、請求體、依賴等的要求。
  • 轉(zhuǎn)換數(shù)據(jù):將來自請求的數(shù)據(jù)轉(zhuǎn)換為需要的類型。
  • 校驗數(shù)據(jù): 對于每一個請求:當(dāng)數(shù)據(jù)校驗失敗時自動生成錯誤信息返回給客戶端。
  • 使用 OpenAPI 記錄 API:然后用于自動生成交互式文檔的用戶界面。

聽上去有點抽象。不過不用擔(dān)心。你將在 教程 - 用戶指南 中看到所有的實戰(zhàn)。

最重要的是,通過使用標(biāo)準(zhǔn)的 Python 類型,只需要在一個地方聲明(而不是添加更多的類、裝飾器等),F(xiàn)astAPI 會為你完成很多的工作。

Info

如果你已經(jīng)閱讀了所有教程,回過頭來想了解有關(guān)類型的更多信息,來自 mypy 的"速查表"是不錯的資源。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號