8000 bpo-44957: Promote PEP 604 syntax in typing docs by srittau · Pull Request #27833 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-44957: Promote PEP 604 syntax in typing docs #27833

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files 8000 .
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -321,11 +321,11 @@ not generic but implicitly inherits from ``Iterable[Any]``::
User defined generic type aliases are also supported. Examples::

from collections.abc import Iterable
from typing import TypeVar, Union
from typing import TypeVar
S = TypeVar('S')
Response = Union[Iterable[S], int]
Response = Iterable[S] | int

# Return type here is same as Union[Iterable[str], int]
# Return type here is same as Iterable[str] | int
def response(query: str) -> Response[str]:
...

Expand Down Expand Up @@ -588,9 +588,9 @@ These can be used as types in annotations using ``[]``, each having a unique syn

.. data:: Union

Union type; ``Union[X, Y]`` means either X or Y.
Union type; ``Union[X, Y]`` is equivalent to ``X | Y`` and means either X or Y.

To define a union, use e.g. ``Union[int, str]``. Details:
To define a union, use e.g. ``Union[int, str]`` or the shorthand ``int | str``. Details:

* The arguments must be types and there must be at least one.
Copy link
Member
@Fidget-Spinner Fidget-Spinner Aug 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, why did you change the redundant arguments are skipped bullet point, but not the others? I can see that Unions of a single argument vanish may not apply directly to the new syntax, but the others do right?

If we manage to merge them, then perhaps we can shorten the contents of the union_object == other section here https://docs.python.org/3.10/library/stdtypes.html#types-union and just link to the typing version. That will save us from some repetition.

Copy link
Contributor Author
@srittau srittau Aug 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went a bit back and forth over this. In the end I decided that most of them apply mostly to Union:

  • Unions of unions don't really exist for PEP 604 unions, except when counting (X | Y) | Z. So we could write one of the following:
    • Union[Union[int, str], float] == Union[int, str, float] == int | str | float
    • Union[Union[int, str], float] == int | str | float
      I kind of like the second one, since it emphasizes the new syntax, but I thought it might be a bit confusing.
  • The redundant arguments should probably be changed to either list both Union[int, str, int] == Union[int, str] and int | str | int == int | str or only the latter (my preference). No idea why I chose this strange middle thing.
  • Same of comparing unions, really.

Copy link
Member
@Fidget-Spinner Fidget-Spinner Aug 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You points make sense. I would like to not outright replace the examples under typing.Union with only the PEP 604 version. For the same reason that we haven't changed examples under typing.List [1] to PEP 585 style list and instead just changed every other use of typing.List elsewhere (same for every other PEP 585-ied type really). Considering at runtime they aren't the same, I'd hate if beginners tripped over some runtime corner case thinking they were. (e.g. isinstance(1, int | str) works, isinstance(1, Union[int, str]) fails before 3.10)

This is one tough pickle :(. So I'm OK with the status quo.

[1] https://docs.python.org/3.11/library/typing.html#typing.List


Expand All @@ -604,18 +604,16 @@ These can be used as types in annotations using ``[]``, each having a unique syn

* Redundant arguments are skipped, e.g.::

Union[int, str, int] == Union[int, str]
Union[int, str, int] == Union[int, str] == int | str
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a critique and slightly off topic: this threw me off a little bit, because in earlier versions of 3.10 this was false because they are different types at runtime. Only since rc1 this is true.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, I didn't know that.

Copy link
Member
@Fidget-Spinner Fidget-Spinner Aug 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the misinformation, but I was wrong 😉 . I think my memory is getting hazy, it was hash(int | str) that wasn't equivalent to hash(Union[int, str]) up till rc1. Equality was there from day 1.


* When comparing unions, the argument order is ignored, e.g.::

Union[int, str] == Union[str, int]

* You cannot subclass or instantiate a union.
* You cannot subclass or instantiate a ``Union``.

* You cannot write ``Union[X][Y]``.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I just noticed this and maybe this can be another PR (since it needs to be backported to 3.9) but isn't this inaccurate if X is a TypeVar?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least the sentence doesn't sound super relevant to me. All examples show how to use Union, so would someone really want to write Union[X][Y]? Maybe this is some historic discussion.


* You can use ``Optional[X]`` as a shorthand for ``Union[X, None]``.

.. versionchanged:: 3.7
Don't remove explicit subclasses from unions at runtime.

Expand All @@ -627,7 +625,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn

Optional type.

``Optional[X]`` is equivalent to ``Union[X, None]``.
``Optional[X]`` is equivalent to ``X | None`` (or ``Union[X, None]``).

Note that this is not the same concept as an optional argument,
which is one that has a default. An optional argument with a
Expand All @@ -644,6 +642,10 @@ These can be used as types in annotations using ``[]``, each having a unique syn
def foo(arg: Optional[int] = None) -> None:
...

.. versionchanged:: 3.10
Optional can now be written as ``X | None``. See
:ref:`union type expressions<types-union>`.

.. data:: Callable

Callable type; ``Callable[[int], str]`` is a function of (int) -> str.
Expand Down Expand Up @@ -770,7 +772,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn
:ref:`type variables <generics>`, and unions of any of these types.
For example::

def new_non_team_user(user_class: Type[Union[BasicUser, ProUser]]): ...
def new_non_team_user(user_class: Type[BasicUser | ProUser]): ...

``Type[Any]`` is equivalent to ``Type`` which in turn is equivalent
to ``type``, which is the root of Python's metaclass hierarchy.
Expand Down Expand Up @@ -951,7 +953,7 @@ These can be used as types in annotations using ``[]``, each having a unique syn
conditional code flow and applying the narrowing to a block of code. The
conditional expression here is sometimes referred to as a "type guard"::

def is_str(val: Union[str, float]):
def is_str(val: str | float):
# "isinstance" type guard
if isinstance(val, str):
# Type of ``val`` is narrowed to ``str``
Expand Down Expand Up @@ -2024,7 +2026,7 @@ Introspection helpers
For a typing object of the form ``X[Y, Z, ...]`` these functions return
``X`` and ``(Y, Z, ...)``. If ``X`` is a generic alias for a builtin or
:mod:`collections` class, it gets normalized to the original class.
If ``X`` is a :class:`Union` or :class:`Literal` contained in another
If ``X`` is a union or :class:`Literal` contained in another
generic type, the order of ``(Y, Z, ...)`` may be different from the order
of the original arguments ``[Y, Z, ...]`` due to type caching.
For unsupported objects return ``None`` and ``()`` correspondingly.
Expand All @@ -2049,7 +2051,7 @@ Introspection helpers
year: int

is_typeddict(Film) # => True
is_typeddict(Union[list, str]) # => False
is_typeddict(list | str) # => False

.. versionadded:: 3.10

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Promote PEP 604 union syntax by using it where possible. Also, mention ``X |
Y`` more prominently in section about ``Union`` and mention ``X | None`` at
all in section about ``Optional``.
0