Skip to main content
Chris | Gizmo | Discord API Engineer

Type hints can be any expression

The official Python grammar doesn't specify a narrowed expression grammar for type annotations. For example, looking at the grammar for a function argument:

arg = (identifier arg, expr? annotation, string? type_comment)

It actually allows any expression to be used for a type annotation. For example, the following code is valid Python syntax:

def foo(t: type) -> type:
    if t is str:
        return int
    else:
        return str


def bar(t: foo(str)) -> foo(int):
    return "wat"


if __name__ == "__main__":
    print(foo(str))
    print(foo(type(None)))

    print(bar(1))

Running that yields the following output:

<class 'int'>
<class 'str'>
wat

Attempting to type check the function with MyPy will result in an error:

-> % mypy test.py
test.py:8: error: Invalid type comment or annotation  [valid-type]
test.py:8: note: Suggestion: use foo[...] instead of foo(...)
Found 1 error in 1 file (checked 1 source file)

Type checking with pyright will result in a similar error.

PEP-484, which specifies type hints in Python, advises that they should be simple expressions but there is nothing in the language itself that stops you from doing this or more absurd examples such as:

def bar(t: (int if foo(str)[-1] + 7 % 2 == 0 else type(None)) = None) -> foo(int):
	...