diff --git a/docs/source/cheat_sheet_py3.rst b/docs/source/cheat_sheet_py3.rst index eb2f8228cf529..7385a66863bf6 100644 --- a/docs/source/cheat_sheet_py3.rst +++ b/docs/source/cheat_sheet_py3.rst @@ -72,9 +72,9 @@ Useful built-in types # On earlier versions, use Union x: list[Union[int, str]] = [3, 5, "test", "fun"] - # Use Optional[X] for a value that could be None - # Optional[X] is the same as X | None or Union[X, None] - x: Optional[str] = "something" if some_condition() else None + # Use X | None for a value that could be None on Python 3.10+ + # Use Optional[X] on 3.9 and earlier; Optional[X] is the same as 'X | None' + x: str | None = "something" if some_condition() else None if x is not None: # Mypy understands x won't be None here because of the if-statement print(x.upper()) @@ -122,13 +122,14 @@ Functions i += 1 # You can of course split a function annotation over multiple lines - def send_email(address: Union[str, list[str]], - sender: str, - cc: Optional[list[str]], - bcc: Optional[list[str]], - subject: str = '', - body: Optional[list[str]] = None - ) -> bool: + def send_email( + address: str | list[str], + sender: str, + cc: list[str] | None, + bcc: list[str] | None, + subject: str = '', + body: list[str] | None = None, + ) -> bool: ... # Mypy understands positional-only and keyword-only arguments @@ -231,7 +232,7 @@ When you're puzzled or when things are complicated # If you initialize a variable with an empty container or "None" # you may have to help mypy a bit by providing an explicit type annotation x: list[str] = [] - x: Optional[str] = None + x: str | None = None # Use Any if you don't know the type of something or it's too # dynamic to write a type for diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index 3d4b841e0a7c8..062739540ade1 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -420,11 +420,11 @@ The following flags adjust how mypy handles values of type ``None``. .. option:: --implicit-optional - This flag causes mypy to treat arguments with a ``None`` - default value as having an implicit :py:data:`~typing.Optional` type. + This flag causes mypy to treat parameters with a ``None`` + default value as having an implicit optional type (``T | None``). For example, if this flag is set, mypy would assume that the ``x`` - parameter is actually of type ``Optional[int]`` in the code snippet below + parameter is actually of type ``int | None`` in the code snippet below, since the default parameter is ``None``: .. code-block:: python @@ -438,7 +438,7 @@ The following flags adjust how mypy handles values of type ``None``. .. option:: --no-strict-optional - This flag effectively disables checking of :py:data:`~typing.Optional` + This flag effectively disables checking of optional types and ``None`` values. With this option, mypy doesn't generally check the use of ``None`` values -- it is treated as compatible with every type. @@ -575,26 +575,24 @@ of the above sections. .. option:: --local-partial-types In mypy, the most common cases for partial types are variables initialized using ``None``, - but without explicit ``Optional`` annotations. By default, mypy won't check partial types + but without explicit ``X | None`` annotations. By default, mypy won't check partial types spanning module top level or class top level. This flag changes the behavior to only allow partial types at local level, therefore it disallows inferring variable type for ``None`` from two assignments in different scopes. For example: .. code-block:: python - from typing import Optional - a = None # Need type annotation here if using --local-partial-types - b: Optional[int] = None + b: int | None = None class Foo: bar = None # Need type annotation here if using --local-partial-types - baz: Optional[int] = None + baz: int | None = None def __init__(self) -> None: self.bar = 1 - reveal_type(Foo().bar) # Union[int, None] without --local-partial-types + reveal_type(Foo().bar) # 'int | None' without --local-partial-types Note: this option is always implicitly enabled in mypy daemon and will become enabled by default for mypy in a future release. diff --git a/docs/source/common_issues.rst b/docs/source/common_issues.rst index c34d20775cfdd..39954b8e332a0 100644 --- a/docs/source/common_issues.rst +++ b/docs/source/common_issues.rst @@ -803,7 +803,7 @@ This is best understood via an example: .. code-block:: python - def foo(x: Optional[int]) -> Callable[[], int]: + def foo(x: int | None) -> Callable[[], int]: if x is None: x = 5 print(x + 1) # mypy correctly deduces x must be an int here diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst index b0e82a33255a6..ded8476b60e35 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -574,8 +574,8 @@ section of the command line docs. :type: boolean :default: False - Causes mypy to treat arguments with a ``None`` - default value as having an implicit :py:data:`~typing.Optional` type. + Causes mypy to treat parameters with a ``None`` + default value as having an implicit optional type (``T | None``). **Note:** This was True by default in mypy versions 0.980 and earlier. @@ -584,7 +584,7 @@ section of the command line docs. :type: boolean :default: True - Effectively disables checking of :py:data:`~typing.Optional` + Effectively disables checking of optional types and ``None`` values. With this option, mypy doesn't generally check the use of ``None`` values -- it is treated as compatible with every type. diff --git a/docs/source/error_code_list.rst b/docs/source/error_code_list.rst index bb745d9d5c986..2739894dd3ec0 100644 --- a/docs/source/error_code_list.rst +++ b/docs/source/error_code_list.rst @@ -59,8 +59,6 @@ Example: .. code-block:: python - from typing import Union - class Cat: def sleep(self) -> None: ... def miaow(self) -> None: ... @@ -69,10 +67,10 @@ Example: def sleep(self) -> None: ... def follow_me(self) -> None: ... - def func(animal: Union[Cat, Dog]) -> None: + def func(animal: Cat | Dog) -> None: # OK: 'sleep' is defined for both Cat and Dog animal.sleep() - # Error: Item "Cat" of "Union[Cat, Dog]" has no attribute "follow_me" [union-attr] + # Error: Item "Cat" of "Cat | Dog" has no attribute "follow_me" [union-attr] animal.follow_me() You can often work around these errors by using ``assert isinstance(obj, ClassName)`` @@ -142,9 +140,7 @@ Example: .. code-block:: python - from typing import Optional - - def first(x: list[int]) -> Optional[int]: + def first(x: list[int]) -> int: return x[0] if x else 0 t = (5, 4) @@ -165,7 +161,7 @@ Example: .. code-block:: python - from typing import overload, Optional + from typing import overload @overload def inc_maybe(x: None) -> None: ... @@ -173,7 +169,7 @@ Example: @overload def inc_maybe(x: int) -> int: ... - def inc_maybe(x: Optional[int]) -> Optional[int]: + def inc_maybe(x: int | None) -> int | None: if x is None: return None else: @@ -273,16 +269,14 @@ Example: .. code-block:: python - from typing import Optional, Union - class Base: def method(self, - arg: int) -> Optional[int]: + arg: int) -> int | None: ... class Derived(Base): def method(self, - arg: Union[int, str]) -> int: # OK + arg: int | str) -> int: # OK ... class DerivedBad(Base): diff --git a/docs/source/generics.rst b/docs/source/generics.rst index 982adf9324afd..9c0a308ee39ab 100644 --- a/docs/source/generics.rst +++ b/docs/source/generics.rst @@ -571,9 +571,9 @@ Let us illustrate this by few simple examples: class Square(Shape): ... * Most immutable container types, such as :py:class:`~collections.abc.Sequence` - and :py:class:`~frozenset` are covariant. :py:data:`~typing.Union` is - also covariant in all variables: ``Union[Triangle, int]`` is - a subtype of ``Union[Shape, int]``. + and :py:class:`~frozenset` are covariant. Union types are + also covariant in all union items: ``Triangle | int`` is + a subtype of ``Shape | int``. .. code-block:: python diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 12422ef85bde4..28a4481e502eb 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -186,19 +186,23 @@ For example, a ``RuntimeError`` instance can be passed to a function that is ann as taking an ``Exception``. As another example, suppose you want to write a function that can accept *either* -ints or strings, but no other types. You can express this using the -:py:data:`~typing.Union` type. For example, ``int`` is a subtype of ``Union[int, str]``: +ints or strings, but no other types. You can express this using a +union type. For example, ``int`` is a subtype of ``int | str``: .. code-block:: python - from typing import Union - - def normalize_id(user_id: Union[int, str]) -> str: + def normalize_id(user_id: int | str) -> str: if isinstance(user_id, int): return f'user-{100_000 + user_id}' else: return user_id +.. note:: + + If using Python 3.9 or earlier, use ``typing.Union[int, str]`` instead of + ``int | str``, or use ``from __future__ import annotations`` at the top of + the file (see :ref:`runtime_troubles`). + The :py:mod:`typing` module contains many other useful types. For a quick overview, look through the :ref:`mypy cheatsheet `. @@ -210,7 +214,7 @@ generic types or your own type aliases), look through the .. note:: When adding types, the convention is to import types - using the form ``from typing import Union`` (as opposed to doing + using the form ``from typing import `` (as opposed to doing just ``import typing`` or ``import typing as t`` or ``from typing import *``). For brevity, we often omit imports from :py:mod:`typing` or :py:mod:`collections.abc` diff --git a/docs/source/kinds_of_types.rst b/docs/source/kinds_of_types.rst index afdf07a559da5..54693cddf953b 100644 --- a/docs/source/kinds_of_types.rst +++ b/docs/source/kinds_of_types.rst @@ -228,6 +228,7 @@ instance of ``C`` or the type of ``C`` itself. This also works with .. _union-types: +.. _alternative_union_syntax: Union types *********** @@ -236,8 +237,8 @@ Python functions often accept values of two or more different types. You can use :ref:`overloading ` to represent this, but union types are often more convenient. -Use the ``Union[T1, ..., Tn]`` type constructor to construct a union -type. For example, if an argument has type ``Union[int, str]``, both +Use ``T1 | ... | Tn`` to construct a union +type. For example, if an argument has type ``int | str``, both integers and strings are valid argument values. You can use an :py:func:`isinstance` check to narrow down a union type to a @@ -245,9 +246,7 @@ more specific type: .. code-block:: python - from typing import Union - - def f(x: Union[int, str]) -> None: + def f(x: int | str) -> None: x + 1 # Error: str + int is not valid if isinstance(x, int): # Here type of x is int. @@ -269,20 +268,38 @@ more specific type: since the caller may have to use :py:func:`isinstance` before doing anything interesting with the value. +Python 3.9 and older only partially support this syntax. Instead, you can +use the legacy ``Union[T1, ..., Tn]`` type constructor. Example: + +.. code-block:: python + + from typing import Union + + def f(x: Union[int, str]) -> None: + ... + +It is also possible to use the new syntax with versions of Python where it +isn't supported by the runtime with some limitations, if you use +``from __future__ import annotations`` (see :ref:`runtime_troubles`): + +.. code-block:: python + + from __future__ import annotations + + def f(x: int | str) -> None: # OK on Python 3.7 and later + ... + .. _strict_optional: Optional types and the None type ******************************** -You can use the :py:data:`~typing.Optional` type modifier to define a type variant -that allows ``None``, such as ``Optional[int]`` (``Optional[X]`` is -the preferred shorthand for ``Union[X, None]``): +You can use ``T | None`` to define a type variant that allows ``None`` values, +such as ``int | None``. This is called an *optional type*: .. code-block:: python - from typing import Optional - - def strlen(s: str) -> Optional[int]: + def strlen(s: str) -> int | None: if not s: return None # OK return len(s) @@ -292,12 +309,23 @@ the preferred shorthand for ``Union[X, None]``): return None # Error: None not compatible with int return len(s) -Most operations will not be allowed on unguarded ``None`` or :py:data:`~typing.Optional` -values: +To support Python 3.9 and earlier, you can use the :py:data:`~typing.Optional` +type modifier instead, such as ``Optional[int]`` (``Optional[X]`` is +the preferred shorthand for ``Union[X, None]``): .. code-block:: python - def my_inc(x: Optional[int]) -> int: + from typing import Optional + + def strlen(s: str) -> Optional[int]: + ... + +Most operations will not be allowed on unguarded ``None`` or *optional* values +(values with an optional type): + +.. code-block:: python + + def my_inc(x: int | None) -> int: return x + 1 # Error: Cannot add None and int Instead, an explicit ``None`` check is required. Mypy has @@ -307,7 +335,7 @@ recognizes ``is None`` checks: .. code-block:: python - def my_inc(x: Optional[int]) -> int: + def my_inc(x: int | None) -> int: if x is None: return 0 else: @@ -323,7 +351,7 @@ Other supported checks for guarding against a ``None`` value include .. code-block:: python - def concat(x: Optional[str], y: Optional[str]) -> Optional[str]: + def concat(x: str | None, y: str | None) -> str | None: if x is not None and y is not None: # Both x and y are not None here return x + y @@ -340,7 +368,7 @@ will complain about the possible ``None`` value. You can use .. code-block:: python class Resource: - path: Optional[str] = None + path: str | None = None def initialize(self, path: str) -> None: self.path = path @@ -363,7 +391,7 @@ This is why you need to annotate an attribute in cases like the class .. code-block:: python class Resource: - path: Optional[str] = None + path: str | None = None ... This also works for attributes defined within methods: @@ -372,10 +400,11 @@ This also works for attributes defined within methods: class Counter: def __init__(self) -> None: - self.count: Optional[int] = None + self.count: int | None = None -This is not a problem when using variable annotations, since no initial -value is needed: +Often it's easier to not use any initial value for an attribute. +This way you don't need to use an optional type and can avoid ``assert ... is not None`` +checks. No initial value is needed if you annotate an attribute in the class body: .. code-block:: python @@ -390,13 +419,13 @@ the right thing without an annotation: .. code-block:: python def f(i: int) -> None: - n = None # Inferred type Optional[int] because of the assignment below + n = None # Inferred type 'int | None' because of the assignment below if i > 0: n = i ... Sometimes you may get the error "Cannot determine type of ". In this -case you should add an explicit ``Optional[...]`` annotation (or type comment). +case you should add an explicit ``... | None`` annotation. .. note:: @@ -414,25 +443,11 @@ case you should add an explicit ``Optional[...]`` annotation (or type comment). .. note:: - ``Optional[...]`` *does not* mean a function argument with a default value. - It simply means that ``None`` is a valid value for the argument. This is - a common confusion because ``None`` is a common default value for arguments. - -.. _alternative_union_syntax: - -X | Y syntax for Unions ------------------------ - -:pep:`604` introduced an alternative way for spelling union types. In Python -3.10 and later, you can write ``Union[int, str]`` as ``int | str``. It is -possible to use this syntax in versions of Python where it isn't supported by -the runtime with some limitations (see :ref:`runtime_troubles`). - -.. code-block:: python - - t1: int | str # equivalent to Union[int, str] - - t2: int | None # equivalent to Optional[int] + The type ``Optional[T]`` *does not* mean a function parameter with a default value. + It simply means that ``None`` is a valid argument value. This is + a common confusion because ``None`` is a common default value for parameters, + and parameters with default values are sometimes called *optional* parameters + (or arguments). .. _type-aliases: @@ -501,7 +516,7 @@ introduced in Python 3.10 (:pep:`613`): from typing import TypeAlias # "from typing_extensions" in Python 3.9 and earlier - AliasType: TypeAlias = Union[list[dict[tuple[int, str], set[int]]], tuple[str, list[str]]] + AliasType: TypeAlias = list[dict[tuple[int, str], set[int]]] | tuple[str, list[str]] .. _named-tuples: diff --git a/docs/source/literal_types.rst b/docs/source/literal_types.rst index 972fce72740fa..877ab5de90877 100644 --- a/docs/source/literal_types.rst +++ b/docs/source/literal_types.rst @@ -70,7 +70,7 @@ complex types involving literals a little more convenient. Literal types may also contain ``None``. Mypy will treat ``Literal[None]`` as being equivalent to just ``None``. This means that ``Literal[4, None]``, -``Union[Literal[4], None]``, and ``Optional[Literal[4]]`` are all equivalent. +``Literal[4] | None``, and ``Optional[Literal[4]]`` are all equivalent. Literals may also contain aliases to other literal types. For example, the following program is legal: diff --git a/docs/source/more_types.rst b/docs/source/more_types.rst index 26edd9ef252c0..cbf40d5dcaa51 100644 --- a/docs/source/more_types.rst +++ b/docs/source/more_types.rst @@ -116,7 +116,7 @@ implicitly casting from ``UserId`` where ``int`` is expected. Examples: :py:class:`~typing.NewType` accepts exactly two arguments. The first argument must be a string literal containing the name of the new type and must equal the name of the variable to which the new type is assigned. The second argument must be a properly subclassable class, i.e., -not a type construct like :py:data:`~typing.Union`, etc. +not a type construct like a :ref:`union type `, etc. The callable returned by :py:class:`~typing.NewType` accepts only one argument; this is equivalent to supporting only one constructor accepting an instance of the base class (see above). @@ -179,7 +179,7 @@ Function overloading ******************** Sometimes the arguments and types in a function depend on each other -in ways that can't be captured with a :py:data:`~typing.Union`. For example, suppose +in ways that can't be captured with a :ref:`union types `. For example, suppose we want to write a function that can accept x-y coordinates. If we pass in just a single x-y coordinate, we return a ``ClickEvent`` object. However, if we pass in two x-y coordinates, we return a ``DragEvent`` object. @@ -188,12 +188,10 @@ Our first attempt at writing this function might look like this: .. code-block:: python - from typing import Union, Optional - def mouse_event(x1: int, y1: int, - x2: Optional[int] = None, - y2: Optional[int] = None) -> Union[ClickEvent, DragEvent]: + x2: int | None = None, + y2: int | None = None) -> ClickEvent | DragEvent: if x2 is None and y2 is None: return ClickEvent(x1, y1) elif x2 is not None and y2 is not None: @@ -213,7 +211,7 @@ to more accurately describe the function's behavior: .. code-block:: python - from typing import Union, overload + from typing import overload # Overload *variants* for 'mouse_event'. # These variants give extra information to the type checker. @@ -236,8 +234,8 @@ to more accurately describe the function's behavior: def mouse_event(x1: int, y1: int, - x2: Optional[int] = None, - y2: Optional[int] = None) -> Union[ClickEvent, DragEvent]: + x2: int | None = None, + y2: int | None = None) -> ClickEvent | DragEvent: if x2 is None and y2 is None: return ClickEvent(x1, y1) elif x2 is not None and y2 is not None: @@ -283,7 +281,7 @@ Here is the same example using the legacy syntax (Python 3.11 and earlier): .. code-block:: python from collections.abc import Sequence - from typing import TypeVar, Union, overload + from typing import TypeVar, overload T = TypeVar('T') @@ -294,7 +292,7 @@ Here is the same example using the legacy syntax (Python 3.11 and earlier): @overload def __getitem__(self, index: slice) -> Sequence[T]: ... - def __getitem__(self, index: Union[int, slice]) -> Union[T, Sequence[T]]: + def __getitem__(self, index: int | slice) -> T | Sequence[T]: if isinstance(index, int): # Return a T here elif isinstance(index, slice): @@ -412,9 +410,9 @@ matching variant returns: .. code-block:: python - some_list: Union[list[int], list[str]] + some_list: list[int] | list[str] - # output3 is of type 'Union[float, str]' + # output3 is of type 'float | str' output3 = summarize(some_list) .. note:: @@ -441,7 +439,7 @@ types: .. code-block:: python - from typing import overload, Union + from typing import overload class Expression: # ...snip... @@ -492,7 +490,7 @@ the following unsafe overload definition: .. code-block:: python - from typing import overload, Union + from typing import overload @overload def unsafe_func(x: int) -> int: ... @@ -500,7 +498,7 @@ the following unsafe overload definition: @overload def unsafe_func(x: object) -> str: ... - def unsafe_func(x: object) -> Union[int, str]: + def unsafe_func(x: object) -> int | str: if isinstance(x, int): return 42 else: @@ -569,8 +567,8 @@ Type checking the implementation The body of an implementation is type-checked against the type hints provided on the implementation. For example, in the ``MyList`` example up above, the code in the body is checked with -argument list ``index: Union[int, slice]`` and a return type of -``Union[T, Sequence[T]]``. If there are no annotations on the +argument list ``index: int | slice`` and a return type of +``T | Sequence[T]``. If there are no annotations on the implementation, then the body is not type checked. If you want to force mypy to check the body anyways, use the :option:`--check-untyped-defs ` flag (:ref:`more details here `). @@ -578,10 +576,10 @@ flag (:ref:`more details here `). The variants must also also be compatible with the implementation type hints. In the ``MyList`` example, mypy will check that the parameter type ``int`` and the return type ``T`` are compatible with -``Union[int, slice]`` and ``Union[T, Sequence]`` for the +``int | slice`` and ``T | Sequence`` for the first variant. For the second variant it verifies the parameter type ``slice`` and the return type ``Sequence[T]`` are compatible -with ``Union[int, slice]`` and ``Union[T, Sequence]``. +with ``int | slice`` and ``T | Sequence``. .. note:: diff --git a/docs/source/protocols.rst b/docs/source/protocols.rst index 8cb53b1fd5cec..ed8d94f62ef15 100644 --- a/docs/source/protocols.rst +++ b/docs/source/protocols.rst @@ -36,11 +36,12 @@ For example, ``IntList`` below is iterable, over ``int`` values: .. code-block:: python + from __future__ import annotations + from collections.abc import Iterator, Iterable - from typing import Optional class IntList: - def __init__(self, value: int, next: Optional['IntList']) -> None: + def __init__(self, value: int, next: IntList | None) -> None: self.value = value self.next = next @@ -237,22 +238,24 @@ such as trees and linked lists: .. code-block:: python - from typing import Optional, Protocol + from __future__ import annotations + + from typing import Protocol class TreeLike(Protocol): value: int @property - def left(self) -> Optional['TreeLike']: ... + def left(self) -> TreeLike | None: ... @property - def right(self) -> Optional['TreeLike']: ... + def right(self) -> TreeLike | None: ... class SimpleTree: def __init__(self, value: int) -> None: self.value = value - self.left: Optional['SimpleTree'] = None - self.right: Optional['SimpleTree'] = None + self.left: SimpleTree | None = None + self.right: SimpleTree | None = None root: TreeLike = SimpleTree(0) # OK @@ -313,15 +316,15 @@ special :py:meth:`__call__ ` member: from typing import Optional, Protocol class Combiner(Protocol): - def __call__(self, *vals: bytes, maxlen: Optional[int] = None) -> list[bytes]: ... + def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes: for item in data: ... - def good_cb(*vals: bytes, maxlen: Optional[int] = None) -> list[bytes]: + def good_cb(*vals: bytes, maxlen: int | None = None) -> list[bytes]: ... - def bad_cb(*vals: bytes, maxitems: Optional[int]) -> list[bytes]: + def bad_cb(*vals: bytes, maxitems: int | None) -> list[bytes]: ... batch_proc([], good_cb) # OK @@ -559,9 +562,9 @@ contextlib.AbstractContextManager[T] def __enter__(self) -> T def __exit__(self, - exc_type: Optional[Type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[TracebackType]) -> Optional[bool] + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None) -> bool | None See also :py:class:`~contextlib.AbstractContextManager`. @@ -572,8 +575,8 @@ contextlib.AbstractAsyncContextManager[T] def __aenter__(self) -> Awaitable[T] def __aexit__(self, - exc_type: Optional[Type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[TracebackType]) -> Awaitable[Optional[bool]] + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None) -> Awaitable[bool | None] See also :py:class:`~contextlib.AbstractAsyncContextManager`. diff --git a/docs/source/runtime_troubles.rst b/docs/source/runtime_troubles.rst index 9e7df05e879e1..d039db30f3fa6 100644 --- a/docs/source/runtime_troubles.rst +++ b/docs/source/runtime_troubles.rst @@ -320,8 +320,8 @@ notes at :ref:`future annotations import`. Using X | Y syntax for Unions ----------------------------- -Starting with Python 3.10 (:pep:`604`), you can spell union types as ``x: int | -str``, instead of ``x: typing.Union[int, str]``. +Starting with Python 3.10 (:pep:`604`), you can spell union types as +``x: int | str``, instead of ``x: typing.Union[int, str]``. There is limited support for using this syntax in Python 3.7 and later as well: if you use ``from __future__ import annotations``, mypy will understand this diff --git a/docs/source/type_inference_and_annotations.rst b/docs/source/type_inference_and_annotations.rst index 6adb4e6512242..318ca4cd91608 100644 --- a/docs/source/type_inference_and_annotations.rst +++ b/docs/source/type_inference_and_annotations.rst @@ -41,12 +41,10 @@ variable type annotation: .. code-block:: python - from typing import Union - - x: Union[int, str] = 1 + x: int | str = 1 Without the type annotation, the type of ``x`` would be just ``int``. We -use an annotation to give it a more general type ``Union[int, str]`` (this +use an annotation to give it a more general type ``int | str`` (this type means that the value can be either an ``int`` or a ``str``). The best way to think about this is that the type annotation sets the type of @@ -55,8 +53,8 @@ about the following code: .. code-block:: python - x: Union[int, str] = 1.1 # error: Incompatible types in assignment - # (expression has type "float", variable has type "Union[int, str]") + x: int | str = 1.1 # error: Incompatible types in assignment + # (expression has type "float", variable has type "int | str") .. note:: diff --git a/docs/source/type_narrowing.rst b/docs/source/type_narrowing.rst index 0f016497113e9..231a7edccfe76 100644 --- a/docs/source/type_narrowing.rst +++ b/docs/source/type_narrowing.rst @@ -123,15 +123,14 @@ So, we know what ``callable()`` will return. For example: else: ... # Will never be executed and will raise error with `--warn-unreachable` -``callable`` function can even split ``Union`` type -for callable and non-callable parts: +The ``callable`` function can even split union types into +callable and non-callable parts: .. code-block:: python from collections.abc import Callable - from typing import Union - x: Union[int, Callable[[], int]] + x: int | Callable[[], int] if callable(x): reveal_type(x) # N: Revealed type is "def () -> builtins.int"