Python: use Type Hints together with Annotations

Viewed 154

In Python, we all know Type hints, which became available from 2015:

def greet(name: str) -> str:
    return "Hello, " + name

and we also know Function Annotations, in particular here I am referring to textual annotations like:

def greet(name: "The name of the person to greet") -> str:
    return "Hello, " + name

But is it possible to use Type Hints together with a textual function annotation?

For example:

def greet(name: str, "The name of the person to greet") -> str:
    return "Hello, " + name

This last one throws an error.

I cannot seem to find any source in PEP or Python docs about whether this would be possible or not. Although I haven't searched particularly deeply, I still would appreciate a source on potential answers.

2 Answers

Since an annotation can be any expression (as far as the Python interpreter is concerned), you can technically do something like using a tuple as your annotation:

def greet(name: (str, "The name of the person to greet")) -> str:
    return "Hello, " + name

which shows up in the function's annotations dict exactly as you'd expect:

>>> greet.__annotations__
{'name': (<class 'str'>, 'The name of the person to greet'), 'return': <class 'str'>}

However, this is only useful if you have tooling that knows what it means. As far as I know, no existing static type checker, linter, doc generator, etc is going to recognize an annotation that's a tuple of a type and a description.

Practically speaking, I'd recommend using the annotation for the type only, since that's overwhelmingly the standard usage, and using comments or docstrings for additional information.

Like Samwise said, type checkers will not understand if the annotation is a tuple of the type and description (or whatever other metadata you wish to attach). PEP 593 – Flexible function and variable annotations addresses exactly this via the following:

from typing import Annotated

@dataclass
class Description:
    x: str

def greet(name: Annotated[str, Description("The name of the person to greet")]) -> str:
    return "Hello, " + name

The reason we introduce a wrapper class Description is so it's clear that the written string is intended to be a description consumed by us, and so other libraries that analyze annotations do not get confused in case they use str for their own metadata.

Then, per typing.Annotated, you can use typing.get_type_hints(name, include_extras=True) to get the description at runtime.

Related