How to Type Hint More Than One Type

How to specify multiple return types using type-hints

From the documentation

class typing.Union

Union type; Union[X, Y] means either X or Y.

Hence the proper way to represent more than one return data type is

from typing import Union

def foo(client_id: str) -> Union[list,bool]

But do note that typing is not enforced. Python continues to remain a dynamically-typed language. The annotation syntax has been developed to help during the development of the code prior to being released into production. As PEP 484 states, "no type checking happens at runtime."

>>> def foo(a:str) -> list:
... return("Works")
...
>>> foo(1)
'Works'

As you can see I am passing a int value and returning a str. However the __annotations__ will be set to the respective values.

>>> foo.__annotations__ 
{'return': <class 'list'>, 'a': <class 'str'>}

Please Go through PEP 483 for more about Type hints. Also see What are type hints in Python 3.5??

Kindly note that this is available only for Python 3.5 and upwards. This is mentioned clearly in PEP 484.


From Python 3.10 onwards, there is a new way to represent this union. See Union Type:

A union object holds the value of the | (bitwise or) operation on multiple type objects. These types are intended primarily for type annotations. The union type expression enables cleaner type hinting syntax compared to typing.Union.

As we can see, this is exactly the same as typing.Union in the previous versions. Our previous example can be modified to use this notation:

def foo(client_id: str) -> list | bool:

Is it possible to type hint more than one type?

Academically, this is called a type union.

Union types in PHP

You can cheat by creating interfaces, parent types, etc, as mentioned in other answers, but what's the point, apart for adding complexity and LoCs to your project? Plus, that can't work for scalar types as you can't extend/implement a scalar type.

Instead of making the code more readable, you'll get the opposite. Except if those classes/interfaces already existed and they are here because of OOP, not to solve a type hinting problem.

Workarounds

The canonical answer in PHP is... well, just don't put a type hint. The language was not thought to have a complex and powerful type system, and trying to workaround the flaws of the language is not a good answer.

Instead, document your function properly:

/**
* Description of what the function does.
*
* @param User|File $multiTypeArgument Description of the argument.
*
* @return string[] Description of the function's return value.
*/
function myFunction($multiTypeArgument)
{

This will at least bring IDE support for autocompletion and static code analysis. Well enough when working on a private project, website, etc.

When designing a public API (a PHP library, etc), sometimes you may want to be more defensive about API consumers' inputs.

Then @tilz0R answer is the way to go:

function log($message) {
if (!is_string($message) && !$message instanceof Message) {
throw new \InvalidArgumentException('$message must be a string or a Message object.');
}

// code ...
}

The day PHP (almost) had union types

The 14th of February 2015, the Union Types PHP RFC was proposed for PHP 7.1. After discussion and vote, it's been rejected, 18 "no" against 11 "yes".

If the RFC had been accepted, PHP would have had union types exactly the way you've shown (User|File).

The RFC had some flaws, but the main reason for why it's been rejected is that the mainteners voters are quite resistive to change especially when it's about type strictness and other programming paradigms (ex. "why would we need type unions when the default takes all types of values" and "that's not good for performance").

How do I specify multiple types for a parameter using type-hints?

You want a type union:

from typing import Union

def post_xml(data: Union[str, ET.Element]):
...

Is there a way to make a type hint for multiple returns

From Python 3.5 to 3.8 you want Tuple[dict, int] in order to specify that you will return both as Python will return them as a tuple.

from typing import Tuple

def rework_data(measurement: dict) -> Tuple[dict, int]:
...
return measurement, 0

As of Python 3.9 Tuple is deprecated and you should use the builtin type

def rework_data(measurement: dict) -> tuple[dict, int]:
...
return measurement, 0

How do I use type hint for multiple classes in a dictionary but they inherit from same parent class?

Depends on how accurate you want your hints to be,

  1. Use the parent class
configurations: Dict[str, Parent] = {
"dev": Dev,
"product": Product,
"test": Test,
}

  1. Specify the classes in a union
from typing import Union
configurations: Dict[str, Union[Dev, Product, Test]] = {
"dev": Dev,
"product": Product,
"test": Test,
}

  1. Create a TypedDict type for this specific dict
from typing import TypedDict

class EnvDict(TypedDict):
dev: Dev
product: Product
test: Test

configurations: EnvDict = {
"dev": Dev,
"product": Product,
"test": Test,
}

Correct type hint for multiple return values

You want to use typing.Union to indicate that the function can return either one type of thing or another. For example, if you had a function that could either return an int or a str, then it's return type would be Union[int, str].

So,

def foo(a: int, b: int, flag: bool) -> Union[int, Tuple[int, int]]:

If you're using Python 3.10, there's a better way to write a union: int | Tuple[int, int]

However, I should repeat the warning given in the comments. Having such a return type is an antipattern and you should refactor your code to avoid this.

Type hinting when multiple types are in input and output but in 1-to-1 relation between them

You have nothing binding your output and input types. At the moment they're entirely unrelated. Try this

AnyEnum = TypeVar("AnyEnum", Enum, IntEnum)

def decode(value: str, enum_class: Type[AnyEnum]) -> AnyEnum:
return make_map(enum_class)[value]

@functools.cache()
def make_map(enum_class: Type[AnyEnum]) -> Dict[str, AnyEnum]:
return {x.name: x for x in enum_class}

Alternatively, @overload should work.

How to annotate types of multiple return values?

You are always returning one object; using return one, two simply returns a tuple.

So yes, -> Tuple[bool, str] is entirely correct.

Only the Tuple type lets you specify a fixed number of elements, each with a distinct type. You really should be returning a tuple, always, if your function produces a fixed number of return values, especially when those values are specific, distinct types.

Other sequence types are expected to have one type specification for a variable number of elements, so typing.Sequence is not suitable here. Also see What's the difference between lists and tuples?

Tuples are heterogeneous data structures (i.e., their entries have different meanings), while lists are homogeneous sequences. Tuples have structure, lists have order.

Python's type hint system adheres to that philosophy, there is currently no syntax to specify an iterable of fixed length and containing specific types at specific positions.

If you must specify that any iterable will do, then the best you can do is:

-> Iterable[Union[bool, str]]

at which point the caller can expect booleans and strings in any order, and of unknown length (anywhere between 0 and infinity).

Last but not least, as of Python 3.9, you can use

-> tuple[bool, str]

instead of -> Tuple[bool, str]; support for type hinting notation has been added to most standard-library container types (see PEP 585 for the complete list). In fact, you can use this as of Python 3.7 too provided you use the from __future__ import annotations compiler switch for your modules and a type checker that supports the syntax.



Related Topics



Leave a reply



Submit