首页 > 编程问答 >为什么 Mypy 会产生这种令人费解的类型检查错误?

为什么 Mypy 会产生这种令人费解的类型检查错误?

时间:2024-07-24 12:00:14浏览次数:7  
标签:python python-typing mypy

为什么下面 test 不进行类型检查(使用Mypy 0.780)?

from typing import Iterator, Tuple

xs: Iterator[int] = (i for i in (1,2,3))
ys: Iterator[int] = (i for i in (1,2,3))
xys: Iterator[Tuple[int,int]] = zip(*(xs,ys))

test: Tuple[int,int,int] = tuple(map(sum, xys))

错误消息:

错误:赋值中的类型不兼容(表达式的类型为“Tuple[Union[_T, int], ...] ", 变量的类型为 "Tuple[int, int, int]")

观察:切换到 Tuple[int, ...] 会消除错误。

评论:我发现这比 test: Tuple[int,int,int] = tuple(range(3)) 类型检查失败更令人惊讶(带有更容易理解的错误消息),但也许是相同的根本问题:长度推断。

编辑:

为了回应@MisterMiyagi的第二条评论,请考虑以下内容,它会引发相同的错误,但显然可以推断长度:

xss: Tuple[Tuple[int,int,int], ...] = tuple((1,2,3) for _ in range(10))
test: Tuple[int,int,int] = tuple(map(sum, zip(*xss)))

Mypy 的错误是由于它无法推断出 zip(*xss) 的结果将始终产生一个长度为 3 的迭代器。让我们逐步分解一下:

  1. xss 的类型: xss 被正确推断为 Tuple[Tuple[int, int, int], ...] ,表示它是一个包含长度可变的元组的元组,其中每个元组都包含三个整数。

  2. zip(*xss) *xss 语法解包了 xss 元组,将其作为单独的参数传递给 zip() 。由于 xss 中的元组数量是未知的(尽管我们知道每个元组都有 3 个元素), zip() 将生成一个长度未知的迭代器。

  3. map(sum, zip(*xss)) 这将对 zip(*xss) 生成的每个元组应用 sum() 函数。由于元组的长度未知, sum() 的结果类型被推断为 Union[_T, int] ,其中 _T sum() 中第一个参数的类型(在这种情况下,它是未知的)。

  4. tuple(...) 这将迭代器的结果转换为元组。但是,由于迭代器长度未知,结果元组的类型变为 Tuple[Union[_T, int], ...] ,表示它是一个包含长度可变的元素的元组,其中每个元素可以是 _T 类型或 int 类型。

  5. 类型不匹配: 最后,将此元组赋值给 test ,其类型为 Tuple[int, int, int] 。由于 Tuple[Union[_T, int], ...] Tuple[int, int, int] 不兼容(前者可能更长或包含不同类型的元素),因此 Mypy 会引发错误。

解决方案:

如所述,将 test 的类型更改为 Tuple[int, ...] 可以解决该错误,因为它允许元组具有任意长度。

另一种解决方案是使用类型提示来帮助 Mypy 推断长度。例如,可以使用 cast() 函数将 zip(*xss) 的结果转换为特定长度的迭代器:

from typing import cast, Iterator, Tuple

xss: Tuple[Tuple[int, int, int], ...] = tuple((1, 2, 3) for _ in range(10))
test: Tuple[int, int, int] = tuple(map(sum, cast(Iterator[Tuple[int, int, int]], zip(*xss))))

这告诉 Mypy, zip(*xss) 的结果实际上是一个长度为 3 的迭代器,从而允许它正确地推断出 test 的类型。

标签:python,python-typing,mypy
From: 62264368

相关文章

  • 如何在Python的matplotlib中将条形标签绘制到右侧并为条形标签添加标题?
    我已经在python中的matplotlib中创建了一个图表,但是以下代码中的最后一行不允许在图表之外对齐条形标签。importmatplotlib.pyplotaspltg=df.plot.barh(x=name,y=days)g.set_title("Dayspeopleshowedup")g.bar_label(g.containers[0],label_type='edge')我得......
  • 19、Python之容器:快来数一数,24678?Counter能数得更好
    引言关于数据的分组计数,前面的文章中已经涉及了很多次。眼下要进行分组计数,我们可用的方法有:1、直接使用dict进行计数,需要对首次出现的键进行判断初始化的操作;2、使用dict的setdefault()方法进行计数,代码可以简化一些,虽然方法名有点怪;3、defaultdict进行计数,可以设置自动......
  • 如何让 Mypy 认识到对两个整数进行排序会返回两个整数
    我的代码如下:fromtypingimportTuplea:Tuple[int,int]=tuple(sorted([1,3]))Mypy告诉我:赋值中的不兼容类型(表达式的类型为“Tuple[int,...]”,变量类型为“Tuple[int,int]”)我做错了什么?为什么Mypy无法弄清楚排序后的元组将返回两个整数?Mypy......
  • 如何使用 C# 检查用户是否安装了最低 Python 版本并且可以访问我的代码?
    我正在开发一个C#程序,该程序必须为一项特定任务运行一些Python代码。(Python代码很复杂,是由另一个团队开发的。无法在C#中重现其功能。)我正在尝试更新我的程序的安装程序文件以解决此问题:我希望它检查用户是否(谁正在安装我的程序)已安装Python并且它满足我的最低版......
  • 如何优雅地将复杂的Python对象和SQLAlchemy对象模型类结合起来?
    我有一个相当复杂的类,具有从提供的df到init计算的复杂属性,这些属性可能是最终可以序列化为字符串的其他类类型。在Python中,我想处理对象而不是原始类型,但也想使用SQLAlchemy与数据库交互。表中的列与许多类属性相同,如何优雅地组合这两个类?我可以使用组合并将数据......
  • Python Match Case:检查未知长度的可迭代内部的类型
    我想使用匹配大小写检查一个未知长度的迭代(假设为list)仅包含给定类型(假设为float)(还有其他情况,只有这个给我带来了问题)。case[*elems]ifall([isinstance(elem,float)foreleminelems]):returnnum这个似乎可行,但确实很不Pythony。看来应该有更简单的方法。......
  • Python实现excel数据的读取和写入
    1.安装说到前面的话,实现excel文件数据的读取和写入,在python中还有其它方法,比如说pandas。鉴于最近粉丝朋友问到上面的“xlrd”和“xlwt”,那么笔者下面将通过这两个方法,来实现excel文件数据的读取和写入。首先,我们先需要提前安装好对应的库。需要注意的是,xlrd从2.0版本开始,只......
  • python_进程与线程_多线程
    一、程序与进程的概念1、进程:指启动后的程序,系统会为进程分配内存空间二、创建进程的方式1、第一种创建进程的方式process(group=None,target,name,args,kwargs)group:表示分组,实际上不使用,默认为None即可target:表示子进程要执行的任务,支持函数名name:表示子进程的......
  • python_网络编程_socket
    一、网络编程的基本概念通信协议:internet协议,任何私有网络支持此协议,就可以接入互联网二、七层协议与四层协议从下到上分别是:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层三、掌握TCP、IP协议ip协议是整个TCP、IP协议族的核心IP地址就是会联网上计算......
  • 你能对 Python 类型注释进行模式匹配吗?
    你能在Python类型上进行模式匹配吗?我见过简单的例子:importbuiltinsmatchx:casebuiltins.str:print("matchedstr")casebuildins.int:print("matchedint")但我想在嵌套类型上进行模式匹配,比如Annotated[Optional[Literal["a",......