提问人:joel 提问时间:8/21/2019 最后编辑:joel 更新时间:11/17/2022 访问量:2285
在 TypeVar 上绑定 TypeVar 的解决方法?
Workaround for TypeVar bound on a TypeVar?
问:
有没有办法用 Python 的类型提示来表达这个 Scala 代码?
trait List[A] {
def ::[B >: A](x: B): List[B]
}
我正在努力实现这种事情
class X: pass
class Y(X): pass
class Z(X): pass
xs = MyList(X(), X()) # inferred as MyList[X]
ys = MyList(Y(), Y()) # inferred as MyList[Y]
_ = xs.extended_by(X()) # inferred as MyList[X]
_ = xs.extended_by(Y()) # inferred as MyList[X]
_ = ys.extended_by(X()) # inferred as MyList[X]
_ = ys.extended_by(Y()) # inferred as MyList[Y]
_ = ys.extended_by(Z()) # inferred as MyList[X]
请注意,该类型初始化为 ,它的类型可以是任何内容。 是不可变的。有关更多详细信息,请参阅注释。MyList
extended_by
MyList
我试过了什么
from __future__ import annotations
from typing import TypeVar, Generic
B = TypeVar('B')
A = TypeVar('A', bound=B)
class MyList(Generic[A]):
def __init__(*o: A):
...
def extended_by(self, x: B) -> MyList[B]:
...
但我明白了(上面是 main.py)
main.py:5:错误:键入变量“main.B“是未绑定
的 main.py:5:注意:(提示:使用”Generic[B]“或”Protocol[B]“基类将”B“绑定到类内) main.py:5:注意:(提示:使用函数签名中的”B“将”B“绑定到函数内部)
Afaict,不允许绑定在.在这种情况下是否有解决方法?TypeVar
答:
-2赞
Cyrille Pontvieux
4/19/2022
#1
from __future__ import annotations
from typing import (
TYPE_CHECKING,
Generic,
TypeVar,
)
B = TypeVar('B')
A = TypeVar('A')
class MyList(Generic[A]):
def __init__(*o: A):
...
def extended_by(self, x: B) -> MyList[B]:
...
class Y:
...
class X:
...
ys = MyList(Y(), Y())
xs = ys.extended_by(X())
if TYPE_CHECKING:
reveal_locals()
这会产生:
test.py:32: note: Revealed local types are:
test.py:32: note: xs: test.MyList[test.X*]
test.py:32: note: ys: test.MyList[test.Y*]
我不明白和 之间的联系。你能举一个例子吗,比如类,这样我就可以更新我的答案了?A
B
Y
X
评论
0赞
joel
4/19/2022
谢谢,但你错过了界限,这是问题的核心。具体来说,with 和 正如你所定义的那样,应该推断为Y
X
xs
MyList[object]
0赞
joel
4/19/2022
有关和A
B
0赞
joel
4/19/2022
我确实明白了你为什么从我说“我正在努力实现这种事情”的部分来到这个解决方案。这是这种边界作用的一个例子,但它缺少 scala trait 的其他一些关键功能
0赞
joel
4/19/2022
我在问题中添加了一个示例
0赞
Cyrille Pontvieux
4/20/2022
因此,如果我理解正确,该方法应该将结果转换为其参数和泛型 A 之间最常见的祖先?我不知道 1.如何在 Python 中做到这一点, 2.用例。extended_by
2赞
Dodezv
11/17/2022
#2
您正在尝试指定 这是 的超类型。但是,与其指定 应该是 的超类型,不如说它是任何类型要容易得多,然后 Union 是您需要的超类型。B
A
B
A
B
A|B
A
from typing import TypeVar, Generic
A = TypeVar("A", covariant=True)
B = TypeVar("B")
class MyList(Generic[A]):
def __init__(*objects: A) -> None: ...
def extended_by(self, other: B) -> MyList[A | B]: ...
class X: pass
class Y(X): pass
class Z(X): pass
xs = MyList(X(), X()) # inferred as MyList[X]
ys = MyList(Y(), Y()) # inferred as MyList[Y]
reveal_type(xs.extended_by(X())) # inferred as MyList[X]
reveal_type(xs.extended_by(Y())) # inferred as MyList[X]
reveal_type(ys.extended_by(X())) # inferred as MyList[X]
reveal_type(ys.extended_by(Y())) # inferred as MyList[Y]
reveal_type(ys.extended_by(Z())) # inferred as MyList[Y|Z]
# MyList[Y|Z] is a subtype of MyList[X]
如果是不可变的,则其类型变量很可能是协变的。这意味着它是 的子类。我冒昧地使您的泛型参数协变,这也将使该方法的实现更容易。MyList
MyList[X]
MyList[Y]
extended_by
注意:如果您必须使用 Python<3.10,请确保替换为 .|
Union
注 2:这与方法相同,例如,请参阅
Typeshed 中的代码。list.__add__
评论
MyList
A
extended_by
A
A
A
C
B
C
A
B
A
C
A
B
C
C
B
C
B