DEV Community

Super Kai (Kazuya Ito)
Super Kai (Kazuya Ito)

Posted on • Edited on

Type hints in Python (1)

Buy Me a Coffee

*Memo:

A type hint:

  • is the optional static type created by single or multiple types for a variable, or function parameter or return value:
    • There are a non-union type and union type because by Python interpreter at runtime which is more important program than type checkers at unruntime, a single type isn't interpreted as Union while multiple types are interpreted as Union:
      • I use the word runtime instead of execution time, running time, etc to mean the time when Python code is running.
      • I use the word unruntime instead of compile time, static analysis time, etc to mean the time before runtime.
  • is for the (static) type checkers such as mypy, pyright, pyrefly, ty, etc so error doesn't occur with Python interpreter even if a type hint is wrong:
  • should be used as specific as possible.
  • can be done with ':', with one or more types and with or without '|' and '[]'.

Basically, I used mypy --strict for the experiments.

       *mypy can be installed with pip install mypy.


A type hint can be done with ':', with one or more types and with or without '|' and '[]' as shown below:

*Memo for '|':

  • '|' can be used from Python 3.10.
  • The type of '|' is Union at runtime:
    • Union is an old way and can still be used.
  • UnionType is the alias of Union from Python 3.14 but currently, using it with mypy gives error as the issue:
    • UnionType is used as one unruntime type which reveal_type() shows:
      • reveal_type() can show both a runtime and unruntime type while type() can show only a runtime type.
  • To set one or more types and None, Optional can also be used from Python 3.10:
  • For Union and UnionType:
    • The 1st arguments are *types(Required-Type:Type):
      • It's one or more types.
      • Don't use any keywords like *types=, types=, etc.
    • Union[str, int, None], UnionType[str, int, None] and str | int | None are equivalent.
  • For Optional:
    • The 1st argument is type(Required-Type:Type):
      • It's a type.
      • Don't use type=.
    • Optional[str], str | None, Union[str, None] and UnionType[str, None] are equivalent.
  • At runtime, the type of:
    • a single type is the non-union type which isn't Union even if using Union, UnionType and Optional.
    • multiple types is the union type which is Union even if using UnionType and Optional.
  • At unruntime, many representations are used whether single or multiple types.

*Memo for '[]':

  • '[]' can be used for iterables(a list, tuple, set, etc), Union, UnionType, Optional, Callable(a function, generator or method), etc.
  • '[]' is required with --strict but optional without --strict.
# from typing import Union
# from types import UnionType

v: str = 'Hello'              # No error
# v: Union[str] = 'Hello'     # No error
# v: UnionType[str] = 'Hello' # Error
# Equivalent

v = 23
v = None
# Error
Enter fullscreen mode Exit fullscreen mode
# from typing import Union, Optional

v: str | int | None = 'Hello'
# v: Union[str, int, None] = 'Hello'
# v: Optional[str | int] = 'Hello'
# Equivalent

v = 23
v = None
# No error

v = 2.3
# Error
Enter fullscreen mode Exit fullscreen mode
# from typing import Union

v: list[int | str] = [0, 'A', 1, 'B', 2]
# v: Union[list[Union[int, str]]] = [0, 'A', 1, 'B', 2]
# Equivalent

v.append('C')
# No error

v.append(3.4)
v = {0, 1, 2}
# Error
Enter fullscreen mode Exit fullscreen mode
# from typing import Union, Optional

def func(name: str, age: int | None = None) -> str | None:
# def func(name: Union[str], age: Union[int, None] = None) -> Union[str]:
# def func(name: str, age: Optional[int] = None) -> str:
    return f'Name:{name}, Age:{age}'           # Equivalent

print(func('John'))              # No error
print(func(name='John'))         # No error
print(func('John', 28))          # No error
print(func(name='John', age=28)) # No error
Enter fullscreen mode Exit fullscreen mode
from typing import Any, Union, Optional, reveal_type

# The runtime type of single type with `type()`
print(type(int))            # <class 'type'>
print(type(None))           # <class 'NoneType'>
print(type(Any))            # <class 'typing._AnyMeta'>
print(type(Union[int]))     # <class 'type'>
print(type(Optional[None])) # <class 'type'>

# The runtime type of multiple types with `type()`
print(type(int | float))       # <class 'typing.Union'>
print(type(None | Any))        # <class 'typing.Union'>
print(type(Union[int, float])) # <class 'typing.Union'>
print(type(Optional[int]))     # <class 'typing.Union'>

# The runtime type of single type with `reveal_type()`
reveal_type(int)            # type
reveal_type(None)           # NoneType
reveal_type(Any)            # _AnyMeta
reveal_type(Union[int])     # type
reveal_type(Optional[None]) # type

# The runtime type of multiple types with `reveal_type()`
reveal_type(int | float)       # Union
reveal_type(None | Any)        # Union
reveal_type(Union[int, float]) # Union
reveal_type(Optional[int])     # Union

# The unruntime type of single type with `reveal_type()`
reveal_type(int)
# Overload(def (builtins.str | _collections_abc.Buffer |
# typing.SupportsInt | typing.SupportsIndex =) -> builtins.int,
# def (builtins.str | builtins.bytes | builtins.bytearray,
# base: typing.SupportsIndex) -> builtins.int)"
reveal_type(None)           # None
reveal_type(Any)            # def () -> typing.Any
reveal_type(Union[int])     # typing._SpecialForm
reveal_type(Optional[None]) # typing._SpecialForm

# The unruntime type of multiple types with `reveal_type()`
reveal_type(int | float)       
# types.UnionType | Overload(def (builtins.str |
# _collections_abc.Buffer | typing.SupportsInt |
# typing.SupportsIndex =) -> builtins.int,
# def (builtins.str | builtins.bytes |
# builtins.bytearray, base: typing.SupportsIndex) -> builtins.int)
reveal_type(None | Any)        # types.UnionType | def () -> typing.Any
reveal_type(Union[int, float]) # typing._SpecialForm
reveal_type(Optional[int])     # typing._SpecialForm
Enter fullscreen mode Exit fullscreen mode

Top comments (0)