zmb*_*mbq 1 python python-typing pylance
我有一个类型T,namedtuple实际上是:
from collections import namedtuple
T = namedtuple('T', ('a', 'b'))
Run Code Online (Sandbox Code Playgroud)
list[T | None]我有一个接受 a和列表的函数:
def func(arg: list[T | None]):
...
l = [T(1, 2), T(2, 3)]
func(l) # Pylance error
Run Code Online (Sandbox Code Playgroud)
l属于 类型list[T]。
当我将 a 传递l给函数时,我从 Pylance 收到错误,指出 a 与list[T]不兼容,list[T | None]因为T cannot be assigned to T | None.
除了手动指定 mylist[T]实际上是 a之外list[T | None],我还能做些什么来使其正常工作而不出错?当然,在运行时一切都会按预期运行。
内置的可变泛型集合类型(例如)的类型参数list都是不变的。(参见PEP 484)
这意味着给定的类型S是 的子类型T,list[S]不是的子类型(也不是超类型)list[T]。
您可以进一步简化您的错误:
def f(a: list[int | None]) -> None: ...
b = [1, 2]
f(b)
Run Code Online (Sandbox Code Playgroud)
int显然是 的子类型int | None,但list[int]不是 的子类型list[int | None]。
对于上面的代码,Mypy 非常友好地提供了额外的信息,准确地告诉我们:
error: Argument 1 to "f" has incompatible type "List[int]"; expected "List[Optional[int]]" [arg-type]
note: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance
note: Consider using "Sequence" instead, which is covariant
Run Code Online (Sandbox Code Playgroud)
除了您之前提到的显式注释列表的明显解决方案之外list[T | None],也许您可以遵循 Mypy 的建议,并将函数接受的类型更改为不太具体的类型,该类型仍然提供您需要的协议,但也恰好是协变的在其类型参数中,例如collections.abc.Sequence:
error: Argument 1 to "f" has incompatible type "List[int]"; expected "List[Optional[int]]" [arg-type]
note: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance
note: Consider using "Sequence" instead, which is covariant
Run Code Online (Sandbox Code Playgroud)
这应该会顺利通过。
附:
您没有提到您的函数到底对该列表做了什么,但是如果您打算在函数内部对其进行变异Sequence,那么具有不可变类型的解决方案显然将不起作用。
可变性确实是这里的问题,也是为什么list首先声明不变的原因。Mypy 文档对此推理提供了非常好的解释。
因此,虽然在技术上可以使用协变类型变量来定义您自己的通用协议,该变量模拟您在该函数中所需的方法,但我不确定这是否是一个好主意。最好重新考虑该函数实际需要什么以及调用它什么是安全的。