在另一个泛型类型中使用泛型类型的参数

Using an Argument to a Generic Type in Another Generic Type

标题可能有点含糊,因为我不确定如何准确表达我想做的事情。

我想在 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 而言,我想用另一种特殊类型 Foo[T] 专门化泛型类型 Bar[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] 并且重复类型非常乏味且容易出错,并且从概念上讲,类 BarBaz 等被认为是不是取决于类型 T 而是取决于特定类型的 Foo[T].

所以如果有能力做这样的事情就好了

MyFoo = Foo[int]
MyBar = Bar[MyFoo]
MyBaz = Baz[MyFoo]

阅读 mypy 文档时,我遇到了这个:Advanced uses of self-types

通过在 Bar 中使用由 Foo 界定的 TypeVar,我们可以指定 Bar 由类似 Foo 的东西参数化。然后,在各个方法中,我们可以使用嵌套类型 Bar[Foo[T]] 注释 self,导致 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[Foo[T]]中的参数T来注释Bar的一个属性。像

class Bar(Generic[Foo[T]]):  # Still invalid.
    item: T

窗台不起作用。

但是,可以通过将属性包装在 属性

中来解决这个问题
class Bar(Generic[S]):
    _item: Any
    
    @property
    def item(self: Bar[Foo[T]]) -> T:
        return self._item

_item 的类型提示不精确为代价。