一日一技:Python类型标注的高级用法

开发 前端
如果传入的参数是int类型的文章id,那么就返回这篇文章的详情ArticleDetail对象。如果传入的是文章列表,那么就返回ArticleDetail对象列表。

假设你正在写后端代码,其中一个函数的功能是传入文章id,返回文章详情。因为项目比较大,因此在定义函数时,把类型标注加上,标明了参数的类型和返回的类型。例如:

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的自动补全就可以正常工作了,如下图所示。

图片图片

你想让这个函数支持批量查询文章详情的功能,代码类似这样:

def query_article_detail(article_id: int | List[int]) -> ArticleDetail | List[ArticleDetail]:
    if isinstance(article_id, int):
        detail = ArticleDetail(
            id=article_id,
            title='文章标题',
            cnotallow='文章内容',
            tag=['tag1', 'tag2']
        )
        return detail
    else:
        details = []
        for _id in article_id:
            detail = ArticleDetail(
                id=_id,
                title='文章标题',
                cnotallow='文章内容',
                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装饰器,实现函数重载来提示。示例代码如下:

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='文章标题',
              cnotallow='文章内容',
              tag=['tag1', 'tag2']
          )
          return detail
      else:
          details = []
          for _id in article_id:
              detail = ArticleDetail(
                  id=_id,
                  title='文章标题',
                  cnotallow='文章内容',
                  tag=['tag1', 'tag2']
              )
              details.append(detail)
          return details

def test_query_article_detail():
    detail = query_article_detail([123, 456, 789])
    print(detail.)

在定义函数之前,先使用@overload装饰器,装饰两次函数名。每一次使用不同的参数:

@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列表时,如下图所示:

图片图片

需要注意的时,所有重载的函数与真正执行的函数,函数名必须全部相同,如下图所示:

图片图片

并且,真正实现功能的函数,必须放在重载函数的下面。

使用这种方式,以后即时别的文件导入并使用你这个函数,你也不用担心它用错数据类型了。

责任编辑:武晓燕 来源: 未闻Code
相关推荐

2021-04-05 14:47:55

Python多线程事件监控

2021-04-12 21:19:01

PythonMakefile项目

2021-04-27 22:15:02

Selenium浏览器爬虫

2021-09-13 20:38:47

Python链式调用

2024-07-30 08:16:18

Python代码工具

2021-03-12 21:19:15

Python链式调用

2024-07-30 08:11:16

2021-07-27 21:32:57

Python 延迟调用

2021-10-15 21:08:31

PandasExcel对象

2022-06-28 09:31:44

LinuxmacOS系统

2022-03-12 20:38:14

网页Python测试

2023-10-29 09:16:49

代码安全命令

2024-02-20 22:13:48

Python项目Java

2020-05-19 13:55:38

Python加密密码

2021-04-23 21:40:33

Python优先级调度器

2023-10-28 12:14:35

爬虫JavaScriptObject

2021-04-19 23:29:44

MakefilemacOSLinux

2022-05-02 16:27:01

JavaScriptHTMLPython

2022-03-07 09:14:04

Selenium鼠标元素

2021-10-03 20:08:29

HTTP2Scrapy
点赞
收藏

51CTO技术栈公众号