【问题标题】:Why does Union of types not resolve to the constrained generic type in Python?为什么类型的联合不能解析为 Python 中的受约束泛型类型?
【发布时间】:2021-08-07 19:25:39
【问题描述】:

我有下面的例子。

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 不兼容。但为什么在这种情况下这是一个问题?我要么是strs序列,要么是ints序列,int和str的兼容性哪来的?

【问题讨论】:

  • 请注意,mypy 在此处失败并出现不同的错误:Value of type variable "IdentifierSymbol" of "f" cannot be "object"。 IIRC MyPy 通过超类型而不是 Union 解析了一个可以被两种类型占据的变量。
  • @MisterMiyagi Huh 我猜 PyLance 有自己的类型检查器。对此感到惊讶。很可能 Union[Sequence[int], Sequence[str]] 解析为 Sequence[object] 或类似的东西,然后什么也找不到。

标签: python python-3.x type-hinting python-typing


【解决方案1】:

至于mypy,那么在当前版本(0.800)中,由于推导类型变量(TypeVar)的特殊性,这不起作用:当它的类型是从多种类型推导时(包括在@987654325中使用的) @ 和 Sequence),它被简化为最接近的公共基本类型。在这种情况下,当 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

【讨论】:

  • 哦,这很有趣,所以基本上我的 Union[Sequence[int], Sequence[str]] 基本上变成了 Sequence[object] 之类的?奇怪。如果我重载初始函数而不是使用 TypeVar,看起来也会发生这种情况,所以我猜 Union 正在做一些奇怪的事情?遗憾的是,如果我在函数签名中只使用一次 TypeVar,PyLance 不喜欢它。但它确实使函数体中的类型警告消失了。
  • "如果我在函数签名中只使用一次 TypeVar,PyLance 不喜欢它。"这条规则对我来说有点模糊。我会通过# type: ignore 禁用它
猜你喜欢
  • 1970-01-01
  • 2012-09-22
  • 1970-01-01
  • 2019-08-24
  • 2016-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多