-
Starting with a really basic generic class: from typing import Generic, TypeVar, Tuple
_T = TypeVar("_T")
class Element(Generic[_T]):
def __init__(self, item: _T):
self.item = item
# e1: Element[str]
e1 = Element("a string")
# e2: Element[int]
e2 = Element(45) we can make a new class that is given an class ContainerOfElement(Generic[_T]):
def __init__(self, element: Element[_T]):
self.element = element
# c1: ContainerOfElement[str]
c1 = ContainerOfElement(e1) my hope for pep-646, which I'm not sure now is covered at all, is the exact same pattern as above, except for a from typing_extensions import TypeVarTuple
from typing_extensions import Unpack
MyTuple = TypeVarTuple("MyTuple")
class ContainerOfMultipleElements(Generic[Unpack[MyTuple]]):
def __init__(self, elements: Tuple[Unpack[MyTuple]]):
"""doesn't work, gives me Element[str] / Element[int] as datatype"""
self.elements = elements
# def __init__(self, elements: Tuple[Unpack[MyTuple[_T] ??? ]]):
# """Need a way to move from MyTuple to _T"""
# self.elements = elements
# desired:
# t1: ContainerOfMultipleElements[str, int]
# what we actually get:
# t1: ContainerOfMultipleElements[Element[str], Element[int]]
t1 = ContainerOfMultipleElements((e1, e2)) |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 8 replies
-
I think what you're looking for is a |
Beta Was this translation helpful? Give feedback.
-
Hi all - Here's a hardcoded way to make my above case work. pyright understands the end result and comes up with the right answer. but it still emits an error that what I'm doing is illegal. @erictraut is there a way to make this work? Shouldn't a pep-646 tuple, when passed around in "unpack" form, be able to be represented in a way that's agnostic of how many elements it has? from typing import Any
from typing import Generic
from typing import Optional
from typing import overload
from typing import TypeVar
from typing_extensions import TypeVarTuple
from typing_extensions import Unpack
_T = TypeVar("_T")
_T1 = TypeVar("_T1")
_T2 = TypeVar("_T2")
_T3 = TypeVar("_T3")
_T4 = TypeVar("_T4")
class Element(Generic[_T]):
def __init__(self, item: _T):
self.item = item
# e1: Element[str]
e1 = Element("a string")
# e2: Element[int]
e2 = Element(45)
e3 = Element("str")
MyTuple = TypeVarTuple("MyTuple")
class ContainerOfMultipleElements(Generic[Unpack[MyTuple]]):
def __init__(self, *elements: Element[Any]):
...
@overload
def container(
e1: Element[_T1], e2: Element[_T2], e3: Element[_T3]
) -> ContainerOfMultipleElements[_T1, _T2, _T3]:
...
@overload
def container(
e1: Element[_T1], e2: Element[_T2]
) -> ContainerOfMultipleElements[_T1, _T2]:
...
@overload
def container(
e1: Element[_T1],
) -> ContainerOfMultipleElements[_T1]:
...
@overload
def container(
e1: Optional[Element[Any]] = None,
e2: Optional[Element[Any]] = None,
e3: Optional[Element[Any]] = None,
*elements: Element[Any],
) -> ContainerOfMultipleElements[Unpack[MyTuple]]:
...
# pylance understands the types, but complains:
#
# Function return type "ContainerOfMultipleElements[_T1@container, _T2@container, _T3@container]" is incompatible with type "ContainerOfMultipleElements[*MyTuple@container]"
# TypeVar "MyTuple@ContainerOfMultipleElements" is invariant
# Element size mismatch; expected 0 but received 3
def container(
e1: Optional[Element[Any]] = None,
e2: Optional[Element[Any]] = None,
e3: Optional[Element[Any]] = None,
*elements: Element[Any],
) -> ContainerOfMultipleElements[Unpack[MyTuple]]:
...
# pylance sees these without issue:
# (variable) t1: ContainerOfMultipleElements[str]
t1 = container(e1)
# (variable) t2: ContainerOfMultipleElements[str, int]
t2 = container(e1, e2)
# (variable) t3: ContainerOfMultipleElements[str, int, str]
t3 = container(e1, e2, e3) |
Beta Was this translation helpful? Give feedback.
I think what you're looking for is a
Map
operation over theTypeVarTuple
contents. There was something like this in an earlier version of PEP 646, but it was removed because the PEP was already very complex. It's something that could be added in a follow-on PEP assuming that 646 is accepted.