我在python中使用了一个Generic类,它的实例很少,但是包含其他类型的实例:
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将导致:
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 --的话,我们将得到:
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]]。
因此,我有两个问题:
Wrapper的行为与Type对Union的行为相同Union的行为有名字吗?如果我们将包装器和联合看作类型上的函数,我们可以说它们是相互通勤,但不确定类型理论中的正确术语是什么,或者具体地说是Python。发布于 2021-09-17 17:39:01
我找到了一个不满意的Q1解决方案,使用了一个带有以下类型分析器钩子的类型插件:
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感觉过度了,但这可能是唯一的办法。
https://stackoverflow.com/questions/69209879
复制相似问题