假设你正在写后端代码,其中一个函数的功能是传入文章id,返回文章详情。因为项目比较大,因此在定义函数时,把类型标注加上,标明了参数的类型和返回的类型。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 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='文章标题', content='文章内容', tag=['tag1', 'tag2'] ) return detail
def test_query_article_detail(): detail = query_article_detail(123) print(detail.content)
|
现在,当你拿到返回的detail变量时,IDE的自动补全就可以正常工作了,如下图所示。
你想让这个函数支持批量查询文章详情的功能,代码类似这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| def query_article_detail(article_id: int | List[int]) -> ArticleDetail | List[ArticleDetail]: if isinstance(article_id, int): detail = ArticleDetail( id=article_id, title='文章标题', content='文章内容', tag=['tag1', 'tag2'] ) return detail else: details = [] for _id in article_id: detail = ArticleDetail( id=_id, title='文章标题', content='文章内容', tag=['tag1', 'tag2'] ) details.append(detail) return details
|
如果传入的参数是int类型的文章id,那么就返回这篇文章的详情ArticleDetail
对象。如果传入的是文章列表,那么就返回ArticleDetail
对象列表。
现在问题来了,由于query_article_detail
函数返回的数据类型不同,如何让IDE的自动补全能够正确提示呢?例如当我们传入了一个文章id列表,但是却直接读取返回数据的.content
属性,在IDE上面看不出任何问题,如下图所示。但显然会报错,因为此时的detail
变量的值是一个列表。列表是没有.content
属性的。
有没有什么办法能够让IDE根据query_article_detail
参数的类型,提示我们对返回数据的使用是否正确呢?
这个场景下,就可以使用Python的typing
模块中的@overload
装饰器,实现函数重载来提示。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| 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='文章标题', content='文章内容', tag=['tag1', 'tag2'] ) return detail else: details = [] for _id in article_id: detail = ArticleDetail( id=_id, title='文章标题', content='文章内容', tag=['tag1', 'tag2'] ) details.append(detail) return details
def test_query_article_detail(): detail = query_article_detail([123, 456, 789]) print(detail.)
|
在定义函数之前,先使用@overload
装饰器,装饰两次函数名。每一次使用不同的参数:
1 2 3 4 5 6 7
| @overload def query_article_detail(article_id: List[int]) -> List[ArticleDetail]: ...
@overload def query_article_detail(article_id: int) -> ArticleDetail: ...
|
这两个函数都是空函数,函数体用三个点代替。当然你也可以使用pass
。而你真正的query_article_detail
放到最下面。现在,当我们对detail
对象使用自动补全时,IDE就能根据参数的类型来补全对应的值了。
当传入参数是单个id时,如下图所示:
当传入的参数是id列表时,如下图所示:
需要注意的时,所有重载的函数与真正执行的函数,函数名必须全部相同,如下图所示:
并且,真正实现功能的函数,必须放在重载函数的下面。
使用这种方式,以后即时别的文件导入并使用你这个函数,你也不用担心它用错数据类型了。