Python 類型提示簡(jiǎn)介

2022-08-20 11:29 更新

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

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

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

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

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

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

Note

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

動(dòng)機(jī)

讓我們從一個(gè)簡(jiǎ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"))

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

John Doe

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

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

修改示例

這是一個(gè)非常簡(jiǎn)單的程序。

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

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

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

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

然后你嘗試向程序員老手的朋友——編輯器自動(dòng)補(bǔ)全尋求幫助。

輸入函數(shù)的第一個(gè)參數(shù) first_name,輸入點(diǎn)號(hào)(.)然后敲下 Ctrl+Space 來觸發(fā)代碼補(bǔ)全。

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

添加類型

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

我們將把下面這段代碼中的函數(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"

這兩者不一樣。

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

而且添加類型提示一般不會(huì)改變?cè)瓉淼倪\(yùn)行結(jié)果。

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

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

這樣,你可以滾動(dòng)查看選項(xiàng),直到你找到看起來眼熟的那個(gè):

更多動(dòng)機(jī)

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

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

因?yàn)榫庉嬈饕呀?jīng)知道了這些變量的類型,所以不僅能對(duì)代碼進(jìn)行補(bǔ)全,還能檢查其中的錯(cuò)誤:

現(xiàn)在你知道了必須先修復(fù)這個(gè)問題,通過 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

聲明類型

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

這也是你將在 FastAPI 中使用它們的主要場(chǎng)景。

簡(jiǎn)單類型

不只是 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)部的值也會(huì)擁有自己的類型。

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

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

列表

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

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

from typing import List


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

同樣以冒號(hào)(:)來聲明這個(gè)變量。

輸入 List 作為類型。

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

from typing import List


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

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

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

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

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

而且,編輯器仍然知道它是一個(gè) 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 是一個(gè) tuple,其中的每個(gè)元素都是 int 類型。
  • 變量 items_s 是一個(gè) set,其中的每個(gè)元素都是 bytes 類型。

字典

定義 dict 時(shí),需要傳入兩個(gè)子類型,用逗號(hào)進(jìn)行分隔。

第一個(gè)子類型聲明 dict 的所有鍵。

第二個(gè)子類型聲明 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 是一個(gè) dict:這個(gè) dict 的所有鍵為 str 類型(可以看作是字典內(nèi)每個(gè)元素的名稱)。這個(gè) dict 的所有值為 float 類型(可以看作是字典內(nèi)每個(gè)元素的價(jià)格)。

類作為類型

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

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

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


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

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

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


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

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

Pydantic 模型

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

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

每個(gè)屬性都擁有類型。

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

然后,你將獲得這個(gè)對(duì)象的所有編輯器支持。

下面的例子來自 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,請(qǐng)閱讀其文檔.

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

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

FastAPI 中的類型提示

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

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

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

...并且 FastAPI 還會(huì)用這些類型聲明來:

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

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

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

Info

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


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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)