Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to annotate variadic parameters in Python using typing annotations?

Tags:

python

pep

typing

How to annotate parameters of the variadic function?

Example:

def foo(*args):  # Each arg expected to be of type T
    ...

Are there any typing annotations for that?

like image 819
kuza Avatar asked Feb 21 '18 15:02

kuza


People also ask

How do you annotate type in Python?

To annotate return value type, add -> immediately after closing the parameter parentheses, just before the function definition colon( : ): def announcement(language: str, version: float) -> str: ... The function now has type hints showing that it receives str and float arguments, and returns str .

What is __ annotations __ in Python?

Annotations were introduced in Python 3.0 originally without any specific purpose. They were simply a way to associate arbitrary expressions to function arguments and return values. Years later, PEP 484 defined how to add type hints to your Python code, based off work that Jukka Lehtosalo had done on his Ph. D.

How do you write a variadic function?

The variadic function consists of at least one fixed variable and then an ellipsis(…) as the last parameter. This enables access to variadic function arguments. *argN* is the last fixed argument in the variadic function. This one accesses the next variadic function argument.

What is the type of * args?

*args allows us to pass a variable number of non-keyword arguments to a Python function. In the function, we should use an asterisk ( * ) before the parameter name to pass a variable number of arguments.


2 Answers

If each argument has a TheType type - annotate it as specified in PEP-484:

def foo(*args: TheType):
    ...

Do not use: def foo(*args: Tuple[TheType]):, because specifying Tuple[TheType] means it's a single-element tuple - with one TheType element, which is not what variadic args are intended to serve.

like image 114
Mikaelblomkvistsson Avatar answered Sep 29 '22 11:09

Mikaelblomkvistsson


tl;dr

Basically args treated as a homogeneous tuple and kwds as a dictionary. You simply annotate a type being expected for each element value.

Explanation

Explanation arrives from quote of the PEP-484:

In the body of function foo, the type of variable args is deduced as Tuple[str, ...] and the type of variable kwds is Dict[str, int].

So there is no need to annotate args as whole homogeneous typed tuple but one can reduce Tuple[T, ...] to just type T.

Same true for the keyword arguments as they deduced as Dict[str, T]

About ellipsis in the tuple annotation

In python documentation there is no much information about the usage of the ... a.k.a Ellipsis but PEP-484 does mention various usages of the ellipsis in typing annotations like for omitting some type annotations or default values but most interestingly there is a qoute saying:

Tuple, used by listing the element types, for example Tuple[int, int, str]. The empty tuple can be typed as Tuple[()]. Arbitrary-length homogeneous tuples can be expressed using one type and ellipsis, for example Tuple[int, ...]. (The ... here are part of the syntax, a literal ellipsis.)

So if you omit asterisk to force passing arguments as a single tuple you need keep full annotation:

def foo(args: Tuple[T, ...]):
    ...

About various types in a homogeneous tuple

Since homogeneous tuple means all of its elements must be of the same type then if you wish to allow several types just use a Union or even use a type alias for better readability:

MyArg = Union[int, str, bool]

def foo(*args: MyArg):
    ...
like image 38
kuza Avatar answered Sep 29 '22 13:09

kuza