为什么类型联合不解析为 Python 中的受约束泛型?

Why does Union of types not resolve to the constrained generic type in Python?

我有下面的例子。

from typing import Union, TypeVar, Dict, Sequence

IdentifierSymbol = TypeVar("IdentifierSymbol", str, int)

def f(ids: Sequence[IdentifierSymbol]) -> Dict[int, IdentifierSymbol]:
    return dict(zip(range(len(ids)), ids))


def g(ids: Union[Sequence[int], Sequence[str]]) -> int:
    x = f(ids)
    return 1

PyLance(我想在里面使用 mypy)在行 x=f(ids):

中抱怨以下内容
Argument of type "Sequence[int] | Sequence[str]" cannot be assigned to parameter "ids" of type "Sequence[IdentifierSymbol@f]" in function "f"
  Type "Sequence[int] | Sequence[str]" cannot be assigned to type "Sequence[IdentifierSymbol@f]"
    TypeVar "_T_co@Sequence" is covariant
      Type "str" is not compatible with constrained type "int" PylancereportGeneralTypeIssues

我不确定如何解释这个,但听起来问题是 int 与 str 不兼容。但为什么在这种情况下这是一个问题?我有一个 str 序列或一个 int 序列,int 和 str 之间的兼容性从何而来?

至于mypy,那么在当前版本(0.800)中,由于推导类型变量的特殊性(TypeVar),这不起作用:当其类型从多个类型推导时(包括在 UnionSequence 中使用的),它被简化为最接近的公共基类型。在这种情况下,当该公共基类型不包含在TypeVar 约束列表中时,将出现错误。

此行为 may change 在未来的版本中。

例如:

class A: ...

class B(A): ...

class C(A): ...

T = TypeVar("T")

def foo(var1: T, var2: T) -> T:
    return var1
    
reveal_type(foo(B(), C()))  # Revealed type is 'main.A*'

def bar(var: T) -> T:
     return var

def baz(var: Union[A, B]):
    reveal_type(bar(var))  # Revealed type is 'main.A*'

def qux(var: Sequence[T]) -> T:
    return var[0]

def quux(var: Tuple[A, B]):
    reveal_type(qux(var))  # Revealed type is 'main.A*'

def quuux(var: Union[Sequence[A], Sequence[B]]):
    reveal_type(qux(var))  # Revealed type is 'main.A*'

您需要使用其他类型注释,例如使 g 函数也通用。也许有人会提出更优雅的解决方案。

def g(ids: Sequence[IdentifierSymbol]) -> int:
    x = f(ids)
    return 1