Python泛型类联合类型分发疑问:Foo[T,A|B]与Foo[T,A]|Foo[T,B]
Python泛型类型特化与联合类型的交互逻辑疑问
问题背景
我正在梳理Python泛型类型特化和联合类型的交互逻辑。针对泛型类Foo[T, U],我原本想通过def op(self: Foo[T, type1 | type2 | ...]) -> rettype的方法签名,让Foo[T, type1]、Foo[T, type2]这类实例都能调用该方法,但实际无法生效,必须把联合类型拆成Foo[T, type1] | Foo[T, type2] | ...的形式才行。
项目动机
Foo类的op方法会返回其他Foo实例,新实例的生成依赖调用者的类型(类似链表节点)。为了支持链式调用(比如foo1.op1().op2().op3()),需要通过类型系统限制不兼容的类型调用对应的op方法。
核心疑问
Python中Foo[T, A | B | C]与Foo[T, A] | Foo[T, B] | Foo[T, C]的类型关系是什么?
测试代码与现象(Python 3.10 + mypy 1.1.1)
# (Python 3.10, Linux, mypy 1.1.1) from __future__ import annotations from typing import Generic, TypeVar, cast import numpy as np T = TypeVar("T") U = TypeVar("U") class Foo(Generic[T, U]): def __init__(self, x: T, y: U): self.x = x self.y = y def op1(self: Foo[T, int | float]) -> float: return self.y * 2.5 def op2(self: Foo[T, float] | Foo[T, int]) -> float: return self.y * 2.5 def op3(self: Foo[T, int | float | str]) -> float: return cast(float, self.y) * 2.5 Foo(0, 1).op1() # error: Invalid self argument "Foo[int, int]" to attribute function "op1" with type "Callable[[Foo[T, Union[int, float]]], float]" [misc] Foo(0, 1.0).op1() # ok: 为什么这个能通过?而下面添加了str类型的op3调用全部失败? Foo(0, "1").op1() # error: Invalid self argument "Foo[int, str]" to attribute function "op1" with type "Callable[[Foo[T, Union[int, float]]], float]" [misc] Foo(0, 1).op2() # ok Foo(0, 1.0).op2() # ok Foo(0, "1").op2() # error: Invalid self argument "Foo[int, str]" to attribute function "op2" with type "Callable[[Union[Foo[T, float], Foo[T, int]]], float]" [misc] Foo(0, 1).op3() # error: Invalid self argument "Foo[int, int]" to attribute function "op3" with type "Callable[[Foo[T, Union[int, float, str]]], float]" [misc] Foo(0, 1.0).op3() # error: Invalid self argument "Foo[int, float]" to attribute function "op3" with type "Callable[[Foo[T, Union[int, float, str]]], float]" [misc] Foo(0, "1").op3() # error: Invalid self argument "Foo[int, str]" to attribute function "op3" with type "Callable[[Foo[T, Union[int, float, str]]], float]" [misc]
具体困惑
我原本以为op1和op2是等价的,但实际op1只允许Foo[T, float]调用,Foo[T, int]调用会报错;而添加了str类型的op3则所有类型调用都报错,这是为什么?
内容的提问来源于stack exchange,提问作者TCM
相关产品推荐
相关产品推荐

