Type of [[1, 2, 3], 3, [2, 4], 5] is list[list[int] | int]. But what type nested list would have if it has undefined depth e.g. [[[1, 2]], 2, [1, [3, [3]]]], 3, [2, [2]]]?
2 Answers
You can define a recursive type alias:
T: TypeAlias = list[Union[int, 'T']]
4 Comments
illuminato
giving the error:
TypeError: unsupported operand type(s) for |: 'type' and 'str'Vladimir Fokow
@illuminato, sorry, my bad. Corrected now
illuminato
Could you please explain what
'T' means? What is the difference between your code and list[Union[int, TypeVar("T")]]?Vladimir Fokow
@illuminato, Unfortunately, I don't understand in full detail. I think
'T' is a forward reference. If you print(T), you see list[typing.Union[int, ForwardRef('T')]]. However, currently mypy complains (by default): "Cannot resolve name "T" (possible cyclic definition)mypy(error)". 3 days ago Support recursive types #731 issue was closed, saying that now we can set a flag -enable-recursive-aliases.Now that PEP 695 was accepted, you can do the following in Python 3.12:
type NestedList = list[int | NestedList]
Note that you can even drop the " around NestedList because it is no longer a forward reference.
You can even make it a generic type so that you can easily get a nested list of, for example, strings instead of integers:
type NestedList[T] = list[T | NestedList[T]]
nest_string_list: NestedList[str] = []
mypy accepts this since version 1.11 if you use the option enable_incomplete_feature = ["NewGenericSyntax"]. I presume that it will be fully supported in the next version.
Union[TypeVar('T'), Iterable[TypeVar('T')]]but in accepted answer another code givenUnion[_, Iterable['_']]. Additionally accepted answer says that "Some types of forward references are handled by PEP0563" without any examples. One comment provide an examplelist[Union[str, "NestedList"]]but it makes it even more confusing becauseNestedListwas not defined in answer. And once again the question itself is not clear for me.TypeVar('T')says it is just a workaround for previous versions of MyPy - so I wouldn't use it.NestedList = list[Union[str, "NestedList"]]wasn't meant to answer the question, but rather to illustrate a point thatNestedList = list[str | "NestedList"]was not supported. However, that comment gives an answer to this question exactly.NestedList = list[Union[str, "NestedList"]]and use it in function definition likedef f(l: NestedList) -> int: ...or do I need to use something likeRecursive: TypeAlias = str | list["Recursive"]withdef f(l: Recursive) -> int: ...instead?