Chris
Chris

Reputation: 485

Why can't List contain multiple types?

You can mix types inside tuples or lists. Why can't you specify that in typing hints?

>>> from typing import Tuple, List
>>> t = ('a', 1)
>>> l = ['a', 1]

>>> t2: Tuple[str, int] = ('a', 1)
>>> l2: List[str, int] = ['a', 1]

TypeError: Too many parameters for typing.List; actual 2, expected 1

Upvotes: 38

Views: 32283

Answers (4)

Pehnny
Pehnny

Reputation: 119

For people reading nowadays : If you're working with Python 3.10 and beyond, typing support has changed quite a bit. Union can be abbreviated by | and you don't need to import typing anymore for most commun classes. So :

from typing import List, Union
my_list : List[Union[str, float]] = ["example", 0, 1, 2]

Is equivalent to :

my_list : list[str | float] = ["example", 0, 1, 2]

You can find every details to PEP 604, PEP 612, PEP 613 and PEP 647

However, if you want to specify the type of each elements of your list you should use a tuple instead which is what a function returns by default. In this case, your types are ordered and separated by commas :

def my_list(text : str, number : float) -> tuple[str, float] :
    return text, number

If you absolutly want a list, you can go for the union notation but your type hinting is not ordered anymore and can lead to a misunderstanding :

def my_list(text : str, number : float) -> list[str | float] :
    return [text, number]

Upvotes: 11

Hultan
Hultan

Reputation: 1549

The answer of using a List and a Union works in some situations, but is prone to causing bugs and is not best pracitce. There is a reason why List doesn't allow multiple types. Let me explain.

Incorrect way

The incorrect way of doing this (like some other answers have written) is this way.

from typing import Union, List
List[Union[str, int]]

There are two issues.

  1. You cannot repeat types multiple times
  2. Type hinting can become inaccurate when the list is updated or changed.

While it might solve it short term, it is not the correct way to use type hinting in python.

Correct way 1: Homogenous lists

This is where you use a list. A list is mutable, so if you add typing, and then change the list, then the typing isn't accurate anymore. You should therefore never use List for different types.

from typing import List
my_list = List[str]

Correct way 2: Non-homogenous tuples

If you actually need to type hint a list, then please use a Tuple. A tuple is immutable and you can therefore be sure that the tuple has the correct types within.

from typing import Tuple
my_list = Tuple[str, int, int, str, int]

Upvotes: 4

chepner
chepner

Reputation: 531075

In type theory, a list is a homogenous structure containing values of one type. As such, List only takes a single type, and every element of that list has to have that type.

However, type theory also provides sum types, which you can think of as a wrapper around exactly one value selected from some fixed set of types. A sum type is supported by typing.Union. To specify that a list is a mix of int and str values, use

List[Union[str, int]]

as the type hint.

By contrast, a tuple is an example of a product type, a type consisting of a fixed set of types, and whose values are a collection of values, one from each type in the product type. Tuple[int,int,int], Tuple[str,int] and Tuple[int,str] are all distinct types, distinguished both by the number of types in the product and the order in which they appear.

Upvotes: 61

juanpa.arrivillaga
juanpa.arrivillaga

Reputation: 95948

You could use a Union, but generally, if you can avoid it, lists should be homogenous instead of heterogeneous:

from typing import List, Union
lst: List[Union[str, int]] = [1, 'a']

myp, at least, will accept this just fine.

This means though that your list accessors will return a Union type, often necessitating handling different possible types in any downstream functions. Accepting unions is generally less problematic.

Upvotes: 15

Related Questions