You can specify recursive types in the typing language by using type aliases and forward reference strings,

Garthoks = Union[Garthok, Iterable['Garthoks']]

Mypy supports recursive types by default since v0.990, and Pyright/Pylance since v2020.9.4.

Some types of forward references are handled by PEP 563. You can use them starting from Python 3.7 by doing from __future__ import annotations – Konstantin


As of Python 3.12, __future__.annotations/stringifying is not necessary if the type is defined using a type statement:

type Garthoks = Garthok | Iterable[Garthoks]
Answer from gilch on Stack Overflow
🌐
Turingtaco
turingtaco.com › recursive-types
Recursive Types in Python - The Turing Taco Tales
December 7, 2024 - Mutually recursive types are declared in Python with forward references, which are strings, and Self Types simplify the Self Recursive case.
Discussions

Generic `typing.ForwardRef` to support generic recursive types - Ideas - Discussions on Python.org
Since v0.981 mypy supports recursive types and will be enabled by default since v0.990. E.g.: JSON = Union[Dict[str, 'JSON'], List['JSON'], str, int, float, bool, None] Recursive types need to use ForwardRefs at the right-hand side to reference the type alias before assignment. More on discuss.python.org
🌐 discuss.python.org
2
October 21, 2022
Recursive type hints
You seem to have a bit of a wrong idea about static type checkers. Mypy only tracks types, not values. That means it has no idea whether test[-1] is a list or an int. As far as mypy is concerned, test[-1] is a Union[int, 'NestedList'], and that can't be assigned to a variable of type NestedList. More on reddit.com
🌐 r/learnpython
5
3
February 25, 2024
Recursive Generic Type Support
Bug Report In: #731 #13297 (not released yet in v0.971) We now support recursive type hints, such as: JSON = Union[Dict[str, 'JSON'], List['JSON'], str, int, float, bool, None] But ... More on github.com
🌐 github.com
1
September 20, 2022
Support recursive types
featuremetaIssues tracking a broad area of workIssues tracking a broad area of workneeds discussionpriority-1-normaltopic-recursive-types More on github.com
🌐 github.com
89
July 30, 2015
🌐
Python.org
discuss.python.org › typing
Recursive type annotation for a nested list of lists of lists of - Typing - Discussions on Python.org
December 11, 2024 - I’m trying to figure out the way to write type annotations to represent a type nested[T,N] such that: nested[T,0] = list[T] nested[T,1] = list[list[T]] nested[T,2] = list[list[list[T]]] etc Is there a good way of doing this? I have hundreds of functions with signatures mostly being like: def func1(p: nested[T,0]) -> T: ... def func2(p: nested[T,0], q: nested[T,0]) -> nested[T,0]: ... def func3(p: nested[T,N], q: nested[T,N], N: int) -> nested[T,N]: ... def func4(p: nested[T,N], ...
🌐
Python.org
discuss.python.org › ideas
Generic `typing.ForwardRef` to support generic recursive types - Ideas - Discussions on Python.org
October 21, 2022 - E.g.: JSON = Union[Dict[str, 'JSON'], List['JSON'], str, int, float, bool, None] Recursive types need to use ForwardRefs at the right-hand side to reference the type alias before assignment.
🌐
Reddit
reddit.com › r/learnpython › recursive type hints
r/learnpython on Reddit: Recursive type hints
February 25, 2024 -

I have lists within lists with integer items (or bytes, but for example purposes ints are enough), for example: [1, 2, [3, 4], 5]

How can I go about creating a type hint for this structure?

This is what I've made:

from typing import List, Union

NestedList = List[Union[int, 'NestedList']]

test: NestedList = [1, 2, [3], 4]
test.append([5])
test = test[-1]

But mypy fails with:

test_recursive_hints.py:7: error: Incompatible types in 
assignment (expression has type "int | NestedList", 
variable has type "NestedList")  [assignment]

How to solve this problem?

🌐
GitHub
github.com › python › mypy › issues › 13693
Recursive Generic Type Support · Issue #13693 · python/mypy
September 20, 2022 - Bug Report In: #731 #13297 (not released yet in v0.971) We now support recursive type hints, such as: JSON = Union[Dict[str, 'JSON'], List['JSON'], str, int, float, bool, None] But ...
Author: python
🌐
MIT
web.mit.edu › 6.005 › www › fa14 › classes › 11-recursive-data-types
Reading 11: Recursive Data Types
In the diagram, we can see how the stack grows as `main` calls `factorial` and `factorial` then calls *itself*, until `factorial(0)` does not make a recursive call. Then the call stack unwinds, each call to `factorial` returning its answer to the caller (where it is assigned to `r`), until `factorial(3)` returns to `main` (where the answer is assigned to `x`). [Here's an **interactive visualization for a Python version of `factorial`**](http://www.pythontutor.com/visualize.html#code=def+factorial(n): ++++if+n+==+0: ++++++++return+1 ++++else: ++++++++r+=+factorial(n-1) ++++++++return+n+*+r x+=+factorial(3) &mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&drawParentPointers=false&textReferences=false&showOnlyOutputs=false&py=2&rawInputLstJSON=[]&curInstr=1).
Find elsewhere
🌐
QuantInsti
blog.quantinsti.com › recursive-functions-python
Recursive Functions in Python: Concepts, Types, and Applications in Trading
June 27, 2024 - In Python, recursive functions can be categorised into different types based on their structure and how they make recursive calls.⁽²⁾
🌐
Hacker News
news.ycombinator.com › item
Last I checked, mypy struggled to represent recursive types. Think `JSON = Union... | Hacker News
May 11, 2021 - Worse, importing third party packages often fails silently and when you can get error messages they tend to be completely inactionable (I recall one error message which linked to a web page that had lots of details and workarounds for fixing other problems, but none of which solved the error itself)
🌐
GitHub
github.com › python › mypy › issues › 731
Support recursive types · Issue #731 · python/mypy
July 30, 2015 - The following in particular would be useful: Callback = Callable[[str], 'Callback'] Foo = Union[str, List['Foo']]
Author: python
🌐
Reddit
reddit.com › r/python › recursive generic type hints (python 3.12)
r/Python on Reddit: Recursive Generic Type Hints (python 3.12)
April 10, 2025 -

TIL from this video typing a recursive flatten (by YT channel anthonywritescode) that you can now type hint recursive data & functions with generic type parameter!

# new syntax
# recursive type for nested list having elems of same type (eg. int)
type _RList[U] = list[U | _RList[U]]

def flatten[T](lst: _RList[T]) -> _RList[T]:
     """ Flatten nested list.""""
     return [
         flatten(x) if isinstance(x, list) else x
         for x in lst
     ]

NOTE: Latest mypy type checks this new syntax, but editor / IDE may not recognize it yet.

Did you all know about this? Have you found more such cool type hinting syntax in Python?

🌐
ScholarHat
scholarhat.com › home › tutorials › python › python recursion: types o..
Python Recursion: Types of Recursion in Python (Full Guide)
September 11, 2025 - Here are the common forms of recursion in Python: Tail Recursion is a unique type of recursion where the recursive call is the last operation in the function. There is no requirement to hold any previous state after the recursive call, allowing for optimization in some languages.
🌐
Sling Academy
slingacademy.com › article › recursive-types-in-modern-python-a-practical-guide
Recursive Types in Modern Python: A Practical Guide - Sling Academy
The typing module in Python 3.5 introduced support for type hints, which can be particularly helpful when working with recursive structures. To correctly type annotate a recursive class, Python 3.7 introduced the from __future__ import annotations feature, allowing for forward references in type hints.
Top answer
1 of 1
1

Assuming that you decide to retain _check_parameters(), here's an illustration of some alternative techniques for organizing a complex boolean check. (1) The isinstance() function will take a tuple of types, so you can do some consolidation. (2) If you need to check for None and check for types, you can do it all in one shot. (3) Some of your checks were repetitive; help the reader by factoring things out. (4) Organize the checks like a pretty-printed data structure because it gets the parens/brackets working for you to convey logical structure. (5) Sometimes simple and fairly banal code comments can function as visual/organizational sign posts to guide the reader. (6) I prefer the lines of code to lead with the substance rather than the boolean operator -- which is mostly a stylistic preference, but I do think it combines better in these kinds of complex checks. For example, I felt no readability-driven urge to add a preliminary True and to the expression. Also, most people use editors with syntax highlighting, so the operators pop out visually and there's no need to waste the prime real estate (the start of each line) on the operator.

TNone = type(None)

check_ctype_seq = lambda ctypes, cls: (
    isinstance(ctypes, cls) and
    all(
        isclass(ct) and
        issubclass(ct, GenericContainer)
        for ct in ctypes
    )
)

return (
    # Length and depth.
    isinstance(length, (int, Callable, TNone)) and
    isinstance(depth, (int, Callable, TNone)) and
    # Matching type.
    (
        isinstance(matching_type, (TNone, type)) or
        is_n_list(matching_type, None, type) or
        is_n_tuple(matching_type, None, type)
    ) and
    # Container_type.
    (
        container_type is None or
        (
            isclass(container_type)
            and issubclass(container_type, GenericContainer)
        ) or
        check_ctype_seq(container_type, list) or
        check_ctype_seq(container_type, tuple)
    )
)
🌐
GitHub
github.com › python › typeshed › issues › 7904
Recursive type aliases tracker · Issue #7904 · python/typeshed
May 21, 2022 - from typing import TypeAlias Recursive: TypeAlias = str | list["Recursive"] def foo(r: Recursive) -> None: if not isinstance(r, str): foo(r[0]) if not isinstance(r, list): r.casefold() foo("") foo(list("")) foo(list(list(""), ""))
Author: python
🌐
LinkedIn
linkedin.com › pulse › recursion-its-types-python-swaroop-shinde
RECURSION & IT'S TYPES IN PYTHON
February 11, 2022 - 🔹 In the above Program, we've used a For Loop to Print Factorial of 5 which is 5 x 4 x 3 x 2 x 1 = 120. Now if we Use Recursion for Same Output, This is how the code looks like :
🌐
Gitbooks
wizardforcel.gitbooks.io › sicp-in-python › content › 18.html
3.3 Recursive Data Structures | SICP in Python - wizardforcel
Recall that the recursive list abstract data type represented a list as a first element and the rest of the list. We previously implemented recursive lists using functions, but at this point we can re-implement them using a class.