Reputation: 10476
Is it possible to create a class like
from typing import Union, Literal
class Foo:
bar: Union[str, int]
qux: Literal["str", "int"]
such that, if qux
is Literal["str"]
, then bar
is of type str
, and if qux
is Literal["int"]
, then bar
is of type int
? Is it possible to annotate that?
I'm aware of typing.overload
, but I don't think it's relevant for this example
Upvotes: 4
Views: 814
Reputation: 50076
Dependent types are not generally supported by Python's typing
system. However, it is possible to emulate some specific cases.
For a low number of dependent types, one can enumerate the cases. This requires making the individual types generic:
from typing import Union, Literal, Generic, TypeVar
Bar = TypeVar("Bar", str, int)
Qux = TypeVar("Qux", Literal["str"], Literal["int"])
class GenericFoo(Generic[Bar, Qux]):
bar: Bar
qux: Qux
# not always needed – used to infer types from instantiation
def __init__(self, bar: Bar, qux: Qux): pass
It is then possible to define the dependency either
Union
of the cases:
Foo = Union[GenericFoo[str, Literal["str"]], GenericFoo[int, Literal["int"]]]
f: Foo
f = GenericFoo("one", "str")
f = GenericFoo(2, "int")
f = GenericFoo("three", "int")
overload
ing the instantiation:
class GenericFoo(Generic[Bar, Qux]):
bar: Bar
qux: Qux
@overload
def __init__(self, bar: str, qux: Literal["str"]):
pass
@overload
def __init__(self, bar: int, qux: Literal["int"]):
pass
def __init__(self, bar: Bar, qux: Qux): # type: ignore
pass
Upvotes: 5