首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >泛型类型与Union类型的相互作用

泛型类型与Union类型的相互作用
EN

Stack Overflow用户
提问于 2021-09-16 14:02:02
回答 1查看 238关注 0票数 2

我在python中使用了一个Generic类,它的实例很少,但是包含其他类型的实例:

代码语言:javascript
运行
复制
import random
from typing import Generic
from typing import TypeVar
from typing import Union

T = TypeVar("T", covariant=True)


class Wrapper(Generic[T]):
    def __init__(self, value: T) -> None:
        self._value = value

    @property
    def unwrap(self) -> T:
        return self._value


def test_union_wrapper() -> None:
    def wrapper_union() -> Wrapper[Union[str, int]]:
        if random.random() >= 0.5:
            return Wrapper("foo")
        else:
            return Wrapper(42)

    # mypy will give an error for this line
    w_u: Union[Wrapper[str], Wrapper[int]] = wrapper_union()

在上面的代码上运行mypy将导致:

代码语言:javascript
运行
复制
error: Incompatible types in assignment (expression has type "Wrapper[Union[str, int]]", variable has type "Union[Wrapper[str], Wrapper[int]]")

这似乎是合理的,因为

Wrapper[Union[str, int]]≮:Wrapper[str]Wrapper[Union[str, int]]≮:Wrapper[int]

和,可以在PEP483中读到

Union在其所有参数中的行为都是共同的。事实上,正如上面所讨论的,如果Union[t1, t2, ...]Union[u1, u2, ...]的子类型,那么t1就是u1的一个子类型,等等。

但我对此表示异议,因为我知道,无论是Wrapper[Union[str, int]] w∈、w∈Wrapper[int]还是w∈Wrapper[int]Wrapper[Union[str, int]]都是<:Union[Wrapper[str], Wrapper[int]]。我想让mypy认识到同样的事实,但我不知道怎么做。

甚至有一个使用标准库进行这种识别的例子。如果我在上面的代码中将Wrapper替换为Type --另一个协变Generic --的话,我们将得到:

代码语言:javascript
运行
复制
def test_union_type() -> None:
    def type_union() -> Type[Union[str, int]]:
        if random.random() >= 0.5:
            return str
        else:
            return int

    # mypy has no problem with this
    w_u: Union[Type[str], Type[int]] = type_union()

在这里,mypy识别函数返回类型,Type[Union[str, int]]等同于变量类型Union[Type[str], Type[int]]

因此,我有两个问题:

  1. 如何告诉类型检查器Wrapper的行为与TypeUnion的行为相同
  2. 这个关于Union的行为有名字吗?如果我们将包装器和联合看作类型上的函数,我们可以说它们是相互通勤,但不确定类型理论中的正确术语是什么,或者具体地说是Python。
EN

回答 1

Stack Overflow用户

发布于 2021-09-17 17:39:01

我找到了一个不满意的Q1解决方案,使用了一个带有以下类型分析器钩子的类型插件:

代码语言:javascript
运行
复制
def commute_with_union_hook(ctx: AnalyzeTypeContext) -> Type:
    sym = ctx.api.lookup_qualified(ctx.type.name, ctx.type)
    node = sym.node
    if not ctx.type.args and len(ctx.type.args) == 1:
        return ctx.api.analyze_type_with_type_info(node, ctx.type.args, ctx.type)

    t: Type = ctx.type.args[0]
    t = ctx.api.anal_type(t)

    if not isinstance(t, UnionType):
        wrapper = ctx.api.analyze_type_with_type_info(node, ctx.type.args, ctx.type)
        return wrapper
    else:
        union_wrapper = UnionType.make_union(
            items=[Instance(typ=node, args=[item]) for item in t.items]
        )
        return union_wrapper

感觉过度了,但这可能是唯一的办法。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69209879

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档