From 6508741a6b40f62c50d6168ce3082b9c6c3be185 Mon Sep 17 00:00:00 2001 From: Nick Crews Date: Sat, 23 Oct 2021 14:55:30 -0600 Subject: [PATCH 1/3] Use list[int] instead of typing.List[int] in generics.rst Also change typing.Tuple to tuple, typing.Dict to dict, etc. Using standard containers is the best practice moving forward, so we should encourage it in examples. I just deleted the info about `typing.List` and friends from the "Generic class internals" section, since that shouldn't be needed going forward, and I wanted to try to keep this doc as slim as possible. --- docs/source/generics.rst | 53 +++++++++++++++------------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/docs/source/generics.rst b/docs/source/generics.rst index f09e0572ee355..962521dc4168f 100644 --- a/docs/source/generics.rst +++ b/docs/source/generics.rst @@ -2,7 +2,7 @@ Generics ======== This section explains how you can define your own generic classes that take -one or more type parameters, similar to built-in types such as ``List[X]``. +one or more type parameters, similar to built-in types such as ``list[X]``. User-defined generics are a moderately advanced feature and you can get far without ever using them -- feel free to skip this section and come back later. @@ -13,8 +13,8 @@ Defining generic classes The built-in collection classes are generic classes. Generic types have one or more type parameters, which can be arbitrary types. For -example, ``Dict[int, str]`` has the type parameters ``int`` and -``str``, and ``List[int]`` has a type parameter ``int``. +example, ``dict[int, str]`` has the type parameters ``int`` and +``str``, and ``list[int]`` has a type parameter ``int``. Programs can also define new generic classes. Here is a very simple generic class that represents a stack: @@ -28,7 +28,7 @@ generic class that represents a stack: class Stack(Generic[T]): def __init__(self) -> None: # Create an empty list with items of type T - self.items: List[T] = [] + self.items: list[T] = [] def push(self, item: T) -> None: self.items.append(item) @@ -40,7 +40,7 @@ generic class that represents a stack: return not self.items The ``Stack`` class can be used to represent a stack of any type: -``Stack[int]``, ``Stack[Tuple[int, str]]``, etc. +``Stack[int]``, ``Stack[tuple[int, str]]``, etc. Using ``Stack`` is similar to built-in container types: @@ -90,19 +90,6 @@ instantiation: >>> print(Stack[int]().__class__) __main__.Stack -Note that built-in types :py:class:`list`, :py:class:`dict` and so on do not support -indexing in Python. This is why we have the aliases :py:class:`~typing.List`, :py:class:`~typing.Dict` -and so on in the :py:mod:`typing` module. Indexing these aliases gives -you a class that directly inherits from the target class in Python: - -.. code-block:: python - - >>> from typing import List - >>> List[int] - typing.List[int] - >>> List[int].__bases__ - (, typing.MutableSequence) - Generic types could be instantiated or subclassed as usual classes, but the above examples illustrate that type variables are erased at runtime. Generic ``Stack`` instances are just ordinary @@ -121,7 +108,7 @@ non-generic. For example: .. code-block:: python - from typing import Generic, TypeVar, Mapping, Iterator, Dict + from typing import Generic, TypeVar, Mapping, Iterator KT = TypeVar('KT') VT = TypeVar('VT') @@ -136,7 +123,7 @@ non-generic. For example: items: MyMap[str, int] # Okay - class StrDict(Dict[str, str]): # This is a non-generic subclass of Dict + class StrDict(dict[str, str]): # This is a non-generic subclass of dict def __str__(self) -> str: return 'StrDict({})'.format(super().__str__()) @@ -284,7 +271,7 @@ For class methods, you can also define generic ``cls``, using :py:class:`Type[T] .. code-block:: python - from typing import TypeVar, Tuple, Type + from typing import TypeVar, Type T = TypeVar('T', bound='Friend') @@ -292,7 +279,7 @@ For class methods, you can also define generic ``cls``, using :py:class:`Type[T] other = None # type: Friend @classmethod - def make_pair(cls: Type[T]) -> Tuple[T, T]: + def make_pair(cls: Type[T]) -> tuple[T, T]: a, b = cls(), cls() a.other = b b.other = a @@ -345,8 +332,8 @@ Let us illustrate this by few simple examples: .. code-block:: python - def salaries(staff: List[Manager], - accountant: Callable[[Manager], int]) -> List[int]: ... + def salaries(staff: list[Manager], + accountant: Callable[[Manager], int]) -> list[int]: ... This function needs a callable that can calculate a salary for managers, and if we give it a callable that can calculate a salary for an arbitrary @@ -363,10 +350,10 @@ Let us illustrate this by few simple examples: def rotate(self): ... - def add_one(things: List[Shape]) -> None: + def add_one(things: list[Shape]) -> None: things.append(Shape()) - my_things: List[Circle] = [] + my_things: list[Circle] = [] add_one(my_things) # This may appear safe, but... my_things[0].rotate() # ...this will fail @@ -532,7 +519,7 @@ Here's a complete example of a function decorator: .. code-block:: python - from typing import Any, Callable, TypeVar, Tuple, cast + from typing import Any, Callable, TypeVar, cast F = TypeVar('F', bound=Callable[..., Any]) @@ -724,11 +711,11 @@ variables replaced with ``Any``. Examples (following :pep:`PEP 484: Type aliases .. code-block:: python - from typing import TypeVar, Iterable, Tuple, Union, Callable + from typing import TypeVar, Iterable, Union, Callable S = TypeVar('S') - TInt = Tuple[int, S] + TInt = tuple[int, S] UInt = Union[S, int] CBack = Callable[..., S] @@ -736,11 +723,11 @@ variables replaced with ``Any``. Examples (following :pep:`PEP 484: Type aliases ... def activate(cb: CBack[S]) -> S: # Same as Callable[..., S] ... - table_entry: TInt # Same as Tuple[int, Any] + table_entry: TInt # Same as tuple[int, Any] T = TypeVar('T', int, float, complex) - Vec = Iterable[Tuple[T, T]] + Vec = Iterable[tuple[T, T]] def inproduct(v: Vec[T]) -> T: return sum(x*y for x, y in v) @@ -748,8 +735,8 @@ variables replaced with ``Any``. Examples (following :pep:`PEP 484: Type aliases def dilate(v: Vec[T], scale: T) -> Vec[T]: return ((x * scale, y * scale) for x, y in v) - v1: Vec[int] = [] # Same as Iterable[Tuple[int, int]] - v2: Vec = [] # Same as Iterable[Tuple[Any, Any]] + v1: Vec[int] = [] # Same as Iterable[tuple[int, int]] + v2: Vec = [] # Same as Iterable[tuple[Any, Any]] v3: Vec[int, int] = [] # Error: Invalid alias, too many type arguments! Type aliases can be imported from modules just like other names. An From 03cfaed8660e3265bd0efb7a334996bc82a8e874 Mon Sep 17 00:00:00 2001 From: Nick Crews Date: Tue, 2 Nov 2021 14:16:04 -0600 Subject: [PATCH 2/3] Keep note about indexing builtins Per https://github.com/python/mypy/pull/11377#pullrequestreview-793658317 --- docs/source/generics.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/source/generics.rst b/docs/source/generics.rst index 962521dc4168f..5f96111fb34fc 100644 --- a/docs/source/generics.rst +++ b/docs/source/generics.rst @@ -90,6 +90,22 @@ instantiation: >>> print(Stack[int]().__class__) __main__.Stack +For Python 3.8 and lower, note that built-in types :py:class:`list`, +:py:class:`dict` and so on do not support indexing in Python. +This is why we have the aliases :py:class:`~typing.List`, :py:class:`~typing.Dict` +and so on in the :py:mod:`typing` module. Indexing these aliases gives +you a class that directly inherits from the target class in Python: + +.. code-block:: python + + >>> # ONLY RELEVANT FOR PYTHON 3.8 AND BELOW + >>> # For Python >=3.9, use normal `list[int]` syntax + >>> from typing import List + >>> List[int] + typing.List[int] + >>> List[int].__bases__ + (, typing.MutableSequence) + Generic types could be instantiated or subclassed as usual classes, but the above examples illustrate that type variables are erased at runtime. Generic ``Stack`` instances are just ordinary From bfdbe8e6f3f4842f737451b28e28d439cedbdabd Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Tue, 2 Nov 2021 13:44:43 -0700 Subject: [PATCH 3/3] Update docs/source/generics.rst --- docs/source/generics.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/generics.rst b/docs/source/generics.rst index 5f96111fb34fc..84582be13f883 100644 --- a/docs/source/generics.rst +++ b/docs/source/generics.rst @@ -98,8 +98,8 @@ you a class that directly inherits from the target class in Python: .. code-block:: python - >>> # ONLY RELEVANT FOR PYTHON 3.8 AND BELOW - >>> # For Python >=3.9, use normal `list[int]` syntax + >>> # Only relevant for Python 3.8 and below + >>> # For Python 3.9 onwards, prefer `list[int]` syntax >>> from typing import List >>> List[int] typing.List[int]