一日一技:Python類型標(biāo)注的高級用法
假設(shè)你正在寫后端代碼,其中一個函數(shù)的功能是傳入文章id,返回文章詳情。因為項目比較大,因此在定義函數(shù)時,把類型標(biāo)注加上,標(biāo)明了參數(shù)的類型和返回的類型。例如:
from typing import List
from dataclasses import dataclass
@dataclass
class ArticleDetail:
id: int
title: str
content: str
tag: List[str]
def query_article_detail(article_id: int) -> ArticleDetail:
detail = ArticleDetail(
id=article_id,
title='文章標(biāo)題',
content='文章內(nèi)容',
tag=['tag1', 'tag2']
)
return detail
def test_query_article_detail():
detail = query_article_detail(123)
print(detail.content)
現(xiàn)在,當(dāng)你拿到返回的detail變量時,IDE的自動補全就可以正常工作了,如下圖所示。
圖片
你想讓這個函數(shù)支持批量查詢文章詳情的功能,代碼類似這樣:
def query_article_detail(article_id: int | List[int]) -> ArticleDetail | List[ArticleDetail]:
if isinstance(article_id, int):
detail = ArticleDetail(
id=article_id,
title='文章標(biāo)題',
cnotallow='文章內(nèi)容',
tag=['tag1', 'tag2']
)
return detail
else:
details = []
for _id in article_id:
detail = ArticleDetail(
id=_id,
title='文章標(biāo)題',
cnotallow='文章內(nèi)容',
tag=['tag1', 'tag2']
)
details.append(detail)
return details
如果傳入的參數(shù)是int類型的文章id,那么就返回這篇文章的詳情ArticleDetail對象。如果傳入的是文章列表,那么就返回ArticleDetail對象列表。
現(xiàn)在問題來了,由于query_article_detail函數(shù)返回的數(shù)據(jù)類型不同,如何讓IDE的自動補全能夠正確提示呢?例如當(dāng)我們傳入了一個文章id列表,但是卻直接讀取返回數(shù)據(jù)的.content屬性,在IDE上面看不出任何問題,如下圖所示。但顯然會報錯,因為此時的detail變量的值是一個列表。列表是沒有.content屬性的。
圖片
有沒有什么辦法能夠讓IDE根據(jù)query_article_detail參數(shù)的類型,提示我們對返回數(shù)據(jù)的使用是否正確呢?
這個場景下,就可以使用Python的typing模塊中的@overload裝飾器,實現(xiàn)函數(shù)重載來提示。示例代碼如下:
from typing import List, overload
from dataclasses import dataclass
@dataclass
class ArticleDetail:
id: int
title: str
content: str
tag: List[str]
@overload
def query_article_detail(article_id: List[int]) -> List[ArticleDetail]:
...
@overload
def query_article_detail(article_id: int) -> ArticleDetail:
...
def query_article_detail(article_id: int | List[int]) -> ArticleDetail | List[ArticleDetail]:
if isinstance(article_id, int):
detail = ArticleDetail(
id=article_id,
title='文章標(biāo)題',
cnotallow='文章內(nèi)容',
tag=['tag1', 'tag2']
)
return detail
else:
details = []
for _id in article_id:
detail = ArticleDetail(
id=_id,
title='文章標(biāo)題',
cnotallow='文章內(nèi)容',
tag=['tag1', 'tag2']
)
details.append(detail)
return details
def test_query_article_detail():
detail = query_article_detail([123, 456, 789])
print(detail.)
在定義函數(shù)之前,先使用@overload裝飾器,裝飾兩次函數(shù)名。每一次使用不同的參數(shù):
@overload
def query_article_detail(article_id: List[int]) -> List[ArticleDetail]:
...
@overload
def query_article_detail(article_id: int) -> ArticleDetail:
...
這兩個函數(shù)都是空函數(shù),函數(shù)體用三個點代替。當(dāng)然你也可以使用pass。而你真正的query_article_detail放到最下面。現(xiàn)在,當(dāng)我們對detail對象使用自動補全時,IDE就能根據(jù)參數(shù)的類型來補全對應(yīng)的值了。
當(dāng)傳入?yún)?shù)是單個id時,如下圖所示:
圖片
當(dāng)傳入的參數(shù)是id列表時,如下圖所示:
圖片
需要注意的時,所有重載的函數(shù)與真正執(zhí)行的函數(shù),函數(shù)名必須全部相同,如下圖所示:
圖片
并且,真正實現(xiàn)功能的函數(shù),必須放在重載函數(shù)的下面。
使用這種方式,以后即時別的文件導(dǎo)入并使用你這個函數(shù),你也不用擔(dān)心它用錯數(shù)據(jù)類型了。