Do union types actually exist in python?

From Python 3.10 onwards, you can use | separator for union types. Taking the example from What's New In Python 3.10:

def square(number: int | float) -> int | float:
    return number ** 2

# Instead of 
def square(number: Union[int, float]) -> Union[int, float]:
    return number ** 2

Also, if you are using Python 3.7+, you can have the feature by using the __future__ package, with some limitations, however:

from __future__ import annotations

# Works in Python 3.7+
def square(number: int | float) -> int | float:
    return number ** 2

# Works only in Python 3.10+
isinstance(3.10, int | float)
numeric = int | float

For more information, see Union Types documentation and PEP 604.


Here are a couple of options to deal with use-cases where you need a tagged union/sum type in Python:

  • Enum + Tuples

    from enum import Enum
    Token = Enum('Token', ['Number', 'Operator', 'Identifier', 'Space', 'Expression'])
    
    (Token.Number, 42)                            # int
    (Token.Operator, '+')                         # str
    (Token.Identifier, 'foo')                     # str
    (Token.Space, )                               # void
    (Token.Expression, ('lambda', 'x', 'x+x'))    # tuple[str]
    

    A slight variation on this uses a dedicated SumType class instead of a tuple:

    from dataclasses import dataclass
    from typing import Any
    
    @dataclass
    class SumType:
        enum: Enum
        data: Any
    
    SumType(Token.Number, 42)
    
  • isinstance

    if isinstance(data, int):
        ...
    if isinstance(data, str):
        ...
    

    Or in combination with the "enum" idea from above:

    token = SumType(Token.Number, 42)
    
    if token.enum == Token.Number:
        ...
    
  • sumtypes module

These approaches all have their various drawbacks, of course.


the type itself does not exist because Python is just a dynamically typed language, however, in newer Python versions, Union Type is an option for Type Hinting,

from typing import Union,TypeVar

T = TypeVar('T')
def f(x: T) -> Union[str, None]:
    if x:
        return "x"

you can use that to annotate your code, thus enabling IDE/Editor level syntax checking.


Union typing is only needed when you have a statically typed language, as you need to declare that an object can return one of multiple types (in your case an int or str, or in the other example str or NoneType).

Python deals in objects only, so there is never a need to even consider 'union types'. Python functions return what they return, if the programmer wants to return different types for different results then that's their choice. The choice is then an architecture choice, and makes no difference to the Python interpreter (so there is nothing to 'benchmark' here).

Python 3.5 does introduce a standard for creating optional type hints, and that standard includes Union[...] and Optional[...] annotations. Type hinting adds optional static type checking outside of the runtime, the same way types in TypeScript are not part of the JavaScript runtime.