标题可能有点含糊,因为我不确定如何准确地表达我想要做的事情。
我想在 python 中从 C++ 复制类似的模式:
template<typename T>
struct Foo
{
using t = T; // Alias T so it can be used in Bar
};
template<typename T>
struct Bar
{
// The type T from Foo<T> can be used as a return type here
typename T::t fn()
{
// do something that returns T::t
}
};
int main(){
// x is determined to be a float
auto x = Bar<Foo<float>>().fn();
};
就Python而言,我想用另一个专用类型
Bar[T]
专门化通用类型Foo[T]
,然后使用用于专门化Foo
的类型在Bar
中输入提示。
类似的东西
from typing import TypeVar, Generic
T = TypeVar("T")
class Foo(Generic[T]):
...
class Bar(Generic[Foo[T]]): # <-- This is illegal
def fn(self) -> T:
...
# In the following, I would like the type checker to know that x is an int.
x = Bar[Foo[int]]().fn()
我知道,如果我们有类似
的东西,那么在创建
Bar
的实例时可以推断出这种关系
class Bar(Generic[T]):
def __init__(self, foo: Foo[T]):
...
但这并不真正适合我当前的问题。
我宁愿能够创建一个专业化系列
Foo[T]
、Bar[T]
、Baz[T]
等,而无需多次重复T
。 在我的实际用例中,类型更像 Foo[R, S, T]
并且重复类型非常乏味且容易出错,并且从概念上讲,类 Bar
、Baz
等被认为不依赖于类型 T
但而是一种特殊类型的Foo[T]
。
所以如果有能力做类似的事情就好了
MyFoo = Foo[int]
MyBar = Bar[MyFoo]
MyBaz = Baz[MyFoo]
阅读 mypy 文档,我发现了这一点:自我类型的高级用途
通过在
TypeVar
中使用以 Foo
为边界的 Bar
,我们可以指定 Bar
由类似 Foo
的东西参数化。 然后,在各个方法中,我们可以使用嵌套类型 self
注释 Bar[Foo[T]]
,从而使 T
绑定到参数化 Foo
参数化 Bar
的参数。
from __future__ import annotations
from typing import TypeVar, Generic
T = TypeVar("T")
class Foo(Generic[T]):
...
# You may want to make `S` covariant with `covariant=True`
# if you plan on using subclasses of `Foo` as parameters to `Bar`.
S = TypeVar("S", bound=Foo)
class Bar(Generic[S]):
def fn(self: Bar[Foo[T]]) -> T:
...
# Below, when binding `fn`, `self` is recognized as
# being of type `Bar[Foo[int]]` which binds `T` as `int`
# and hence the return type is also `int`.
x = Bar[Foo[int]]().fn()
我一直无法弄清楚的是如何使用
Bar
中的参数T
来注释Bar[Foo[T]]
的属性。 类似的东西
class Bar(Generic[Foo[T]]): # Still invalid.
item: T
sill 不起作用。
但是,可以通过将属性包装在属性中来解决这个问题
class Bar(Generic[S]):
_item: Any
@property
def item(self: Bar[Foo[T]]) -> T:
return self._item
以类型提示
_item
不精确为代价。