The title might be a bit ambiguous as I'm not sure how to phrase what I am trying to do exactly.
I would like to replicate something like this pattern from C++ in python:
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();
};
In terms of python, I would like to specialize a generic type Bar[T] with another specialized type Foo[T] and then use the type that was used to specialize Foo to type hint in Bar.
Something like
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()
I know that this relationship can be deduced when creating instances of Bar if we have something like
class Bar(Generic[T]):
def __init__(self, foo: Foo[T]):
...
but that doesn't really fit my current problem.
I would rather like to be able to create a family of specializations Foo[T], Bar[T], Baz[T], etc without having repeat T many times. In my real use case the types are more like Foo[R, S, T] and repeating the types is quite tedious and error prone and, conceptually, classes Bar, Baz, etc are thought of not as depending on a type T but rather a particular type of Foo[T].
So it would be nice to have the ability to do something like
MyFoo = Foo[int]
MyBar = Bar[MyFoo]
MyBaz = Baz[MyFoo]