gpt4 book ai didi

python - 为什么在 Pycharm 中连接混合类型列表时会收到警告?

转载 作者:太空宇宙 更新时间:2023-11-03 15:33:12 25 4
gpt4 key购买 nike

在 Pycharm 中,以下代码会产生警告:

from typing import List

list1: List[int] = [1, 2, 3]
list2: List[str] = ["1", "2", "3"]
list3: List[object] = list1 + list2
# ↳ Expected type List[int] (matched generic type List[_T]),
# got List[str] instead.

为什么?我不应该连接两个混合的、暗示类型的列表吗?

最佳答案

根据评论中的要求,以下是类型检查器不允许这样做的一些原因。

第一个原因有点平淡无奇:list.__add__ 的类型签名根本不允许传入包含相同类型的列表以外的任何内容:

_T = TypeVar('_T')

# ...snip...

class list(MutableSequence[_T], Generic[_T]):

# ...snip...

def __add__(self, x: List[_T]) -> List[_T]: ...

而支持 PEP 484 的 Pycharm 使用(部分)来自 Typeshed 的数据。

我们有可能以某种方式扩展此类型签名(例如,重载它以也接受 List[_S] 并返回 List[Union[_T, _S]] 在那种情况下),但我认为没有人会费心去研究这种方法的可行性:这种东西在实践中不是很有用,让那些想要严格同质列表或想要子类化它们的人的生活更加艰难,并且可能会破坏很多依赖于当前类型签名的现有代码。

此类型签名也可能反射(reflect)了在 PEP 484 的初始设计期间做出的更广泛的选择,即假设列表始终是同质的——始终包含相同类型的值。

严格来说,PEP 484 的设计者不需要做出这个选择:他们可能需要类型检查器来与它进行特殊情况的交互,就像我们目前对元组所做的那样。但我认为不这样做总体上更简单。 (也可以说是更好的风格,但无论如何。)


第二个原因与 PEP 484 类型系统的基本限制有关:无法声明某些函数或方法不修改状态。

基本上,只有当 lst1.__add__(lst2) 保证不会改变任何一个操作数时,您想要的行为才是安全的。但是实际上没有办法保证这一点——如果 lst1 是一些奇怪的列表子类,它将项目从 lst2 复制到它自己呢?然后暂时将 lst1 的类型从 SomeListSubtype[int] 放宽到 SomeListSubtype[object] 是不安全的:lst1添加/注入(inject)来自 lst2 的字符串后将不再仅包含整数。

当然,实际上编写这样一个子类也是不好的做法,但是类型检查器没有奢侈地假设用户会遵循最佳实践,如果不强制执行的话:类型检查器、编译器和类似工具从根本上来说是保守的野兽。


最后,值得注意的是,这些问题在本质上都不是无法克服的。类型检查器实现者可以做几件事,例如:

  1. 修改列表的类型签名(并确保它不会破坏任何现有代码)
  2. 引入某种方式来声明一个方法是纯粹的——没有突变。基本上概括一下背后的思路PEP 591也适用于功能。 (但这需要编写 PEP、修改类型以使用新的类型构造、进行大量仔细的设计和实现工作……)
  3. 当我们确定这两个变量不是列表的子类时,也许可以对这种交互进行特殊处理。 (但实际上,我们确定知道这一点的次数非常有限。)

...等等。

但是所有这些事情都需要时间和精力来完成:这是一个优先顺序的问题。 PyCharm(和 mypy 等)的问题跟踪器很长,并且不乏其他需要解决的错误/功能请求。

关于python - 为什么在 Pycharm 中连接混合类型列表时会收到警告?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56738485/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com