Skip to content
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

Various doc updates, mostly about list[t] etc. #9936

Merged
merged 6 commits into from Jan 21, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
95 changes: 72 additions & 23 deletions docs/source/builtin_types.rst
@@ -1,45 +1,94 @@
Built-in types
==============

These are examples of some of the most common built-in types:
This chapter introduces some commonly used built-in types. We will
cover many other kinds of types later.

Simple types
............

Here are examples of some common built-in types:

====================== ===============================
Type Description
====================== ===============================
``int`` integer
``float`` floating point number
``bool`` boolean value (subclass of ``int``)
``str`` string (unicode)
``str`` string (unicode in Python 3)
``bytes`` 8-bit string
``object`` an arbitrary object (``object`` is the common base class)
====================== ===============================

All built-in classes can be used as types.

Any type
........

If you can't find a good type for some value, you can always fall back
to ``Any``:

====================== ===============================
Type Description
====================== ===============================
``Any`` dynamically typed value with an arbitrary type
====================== ===============================

The type ``Any`` is defined in the :py:mod:`typing` module.
See :ref:`dynamic-typing` for more details.

Generic types
.............

In Python 3.9 and later, built-in collection type objects support
indexing:

====================== ===============================
Type Description
====================== ===============================
``list[str]`` list of ``str`` objects
``tuple[int, int]`` tuple of two ``int`` objects (``tuple[()]`` is the empty tuple)
``tuple[int, ...]`` tuple of an arbitrary number of ``int`` objects
``dict[str, int]`` dictionary from ``str`` keys to ``int`` values
``Iterable[int]`` iterable object containing ints
``Sequence[bool]`` sequence of booleans (read-only)
``Mapping[str, int]`` mapping from ``str`` keys to ``int`` values (read-only)
====================== ===============================

The type ``dict`` is a *generic* class, signified by type arguments within
``[...]``. For example, ``dict[int, str]`` is a dictionary from integers to
strings and ``dict[Any, Any]`` is a dictionary of dynamically typed
(arbitrary) values and keys. ``list`` is another generic class.

``Iterable``, ``Sequence``, and ``Mapping`` are generic types that correspond to
Python protocols. For example, a ``str`` object or a ``list[str]`` object is
valid when ``Iterable[str]`` or ``Sequence[str]`` is expected.
You can import them from :py:mod:`collections.abc` instead of importing from
:py:mod:`typing` in Python 3.9.

See :ref:`generic-builtins` for more details, including how you can
use these in annotations also in Python 3.7 and 3.8.

These legacy types defined in :py:mod:`typing` are needed if you need to support
Python 3.8 and earlier:

====================== ===============================
Type Description
====================== ===============================
``List[str]`` list of ``str`` objects
``Tuple[int, int]`` tuple of two ``int`` objects (``Tuple[()]`` is the empty tuple)
``Tuple[int, ...]`` tuple of an arbitrary number of ``int`` objects
``Dict[str, int]`` dictionary from ``str`` keys to ``int`` values
``Iterable[int]`` iterable object containing ints
``Sequence[bool]`` sequence of booleans (read-only)
``Mapping[str, int]`` mapping from ``str`` keys to ``int`` values (read-only)
``Any`` dynamically typed value with an arbitrary type
====================== ===============================

The type ``Any`` and type constructors such as ``List``, ``Dict``,
``Iterable`` and ``Sequence`` are defined in the :py:mod:`typing` module.
``List`` is an alias for the built-in type ``list`` that supports
indexing (and similarly for ``dict``/``Dict`` and
``tuple``/``Tuple``).

The type ``Dict`` is a *generic* class, signified by type arguments within
``[...]``. For example, ``Dict[int, str]`` is a dictionary from integers to
strings and ``Dict[Any, Any]`` is a dictionary of dynamically typed
(arbitrary) values and keys. ``List`` is another generic class. ``Dict`` and
``List`` are aliases for the built-ins ``dict`` and ``list``, respectively.

``Iterable``, ``Sequence``, and ``Mapping`` are generic types that correspond to
Python protocols. For example, a ``str`` object or a ``List[str]`` object is
valid when ``Iterable[str]`` or ``Sequence[str]`` is expected. Note that even
though they are similar to abstract base classes defined in
:py:mod:`collections.abc` (formerly ``collections``), they are not identical. In
particular, prior to Python 3.9, the built-in collection type objects do not
support indexing.

In Python 3.9 and later, built-in collection type objects support indexing. This
means that you can use built-in classes or those from :py:mod:`collections.abc`
instead of importing from :py:mod:`typing`. See :ref:`generic-builtins` for more
details.
Note that even though ``Iterable``, ``Sequence`` and ``Mapping`` look
similar to abstract base classes defined in :py:mod:`collections.abc`
(formerly ``collections``), they are not identical, since the latter
don't support indexing prior to Python 3.9.
14 changes: 11 additions & 3 deletions docs/source/cheat_sheet_py3.rst
Expand Up @@ -54,21 +54,29 @@ Built-in types
x: str = "test"
x: bytes = b"test"

# For collections, the name of the type is capitalized, and the
# name of the type inside the collection is in brackets
# For collections, the type of the collection item is in brackets
# (Python 3.9+)
x: list[int] = [1]
x: set[int] = {6, 7}

# In Python 3.8 and earlier, the name of the collection type is
# capitalized, and the type is imported from 'typing'
x: List[int] = [1]
x: Set[int] = {6, 7}

# Same as above, but with type comment syntax
# Same as above, but with type comment syntax (Python 3.5 and earlier)
x = [1] # type: List[int]

# For mappings, we need the types of both keys and values
x: dict[str, float] = {'field': 2.0} # Python 3.9+
x: Dict[str, float] = {'field': 2.0}

# For tuples of fixed size, we specify the types of all the elements
x: tuple[int, str, float] = (3, "yes", 7.5) # Python 3.9+
x: Tuple[int, str, float] = (3, "yes", 7.5)

# For tuples of variable size, we use one type and ellipsis
x: tuple[int, ...] = (1, 2, 3) # Python 3.9+
x: Tuple[int, ...] = (1, 2, 3)

# Use Optional[] for values that could be None
Expand Down
1 change: 1 addition & 0 deletions docs/source/config_file.rst
Expand Up @@ -538,6 +538,7 @@ section of the command line docs.
:default: False

Disallows inferring variable type for ``None`` from two assignments in different scopes.
This is always implicitly enabled when using the :ref:`mypy daemon <mypy_daemon>`.

.. confval:: disable_error_code

Expand Down
70 changes: 48 additions & 22 deletions docs/source/getting_started.rst
Expand Up @@ -160,22 +160,19 @@ Arguments with default values can be annotated like so:
for key, value in kwargs:
print(key, value)

The typing module
*****************
Additional types, and the typing module
***************************************

So far, we've added type hints that use only basic concrete types like
``str`` and ``float``. What if we want to express more complex types,
such as "a list of strings" or "an iterable of ints"?

You can find many of these more complex static types inside of the :py:mod:`typing`
module. For example, to indicate that some function can accept a list of
strings, use the :py:class:`~typing.List` type:
For example, to indicate that some function can accept a list of
strings, use the ``list[str]`` type (Python 3.9 and later):

.. code-block:: python

from typing import List

def greet_all(names: List[str]) -> None:
def greet_all(names: list[str]) -> None:
for name in names:
print('Hello ' + name)

Expand All @@ -185,20 +182,38 @@ strings, use the :py:class:`~typing.List` type:
greet_all(names) # Ok!
greet_all(ages) # Error due to incompatible types

The :py:class:`~typing.List` type is an example of something called a *generic type*: it can
accept one or more *type parameters*. In this case, we *parameterized* :py:class:`~typing.List`
by writing ``List[str]``. This lets mypy know that ``greet_all`` accepts specifically
The ``list`` type is an example of something called a *generic type*: it can
accept one or more *type parameters*. In this case, we *parameterized* ``list``
by writing ``list[str]``. This lets mypy know that ``greet_all`` accepts specifically
lists containing strings, and not lists containing ints or any other type.

In this particular case, the type signature is perhaps a little too rigid.
In Python 3.8 and earlier, you can instead import the
:py:class:`~typing.List` type from the :py:mod:`typing` module:

.. code-block:: python

from typing import List # Python 3.8 and earlier

def greet_all(names: List[str]) -> None:
for name in names:
print('Hello ' + name)

...

You can find many of these more complex static types in the :py:mod:`typing` module.

In the above examples, the type signature is perhaps a little too rigid.
After all, there's no reason why this function must accept *specifically* a list --
it would run just fine if you were to pass in a tuple, a set, or any other custom iterable.

You can express this idea using the :py:class:`~typing.Iterable` type instead of :py:class:`~typing.List`:
You can express this idea using the
:py:class:`collections.abc.Iterable` type instead of
:py:class:`~typing.List` (or :py:class:`typing.Iterable` in Python
3.8 and earlier):

.. code-block:: python

from typing import Iterable
from collections.abc import Iterable # or "from typing import Iterable"

def greet_all(names: Iterable[str]) -> None:
for name in names:
Expand Down Expand Up @@ -239,13 +254,21 @@ and a more detailed overview (including information on how to make your own
generic types or your own type aliases) by looking through the
:ref:`type system reference <overview-type-system-reference>`.

One final note: when adding types, the convention is to import types
using the form ``from typing import Iterable`` (as opposed to doing
just ``import typing`` or ``import typing as t`` or ``from typing import *``).
.. note::

When adding types, the convention is to import types
using the form ``from typing import Union`` (as opposed to doing
just ``import typing`` or ``import typing as t`` or ``from typing import *``).

For brevity, we often omit these :py:mod:`typing` imports in code examples, but
mypy will give an error if you use types such as :py:class:`~typing.Iterable`
without first importing them.
For brevity, we often omit imports from :py:mod:`typing` or :py:mod:`collections.abc`
in code examples, but mypy will give an error if you use types such as
:py:class:`~typing.Iterable` without first importing them.

.. note::

In some examples we use capitalized variants of types, such as
``List``, and sometimes we use plain ``list``. They are equivalent,
but the prior variant is needed if you are not using a recent Python.

Local type inference
********************
Expand All @@ -267,7 +290,7 @@ of type ``List[float]`` and that ``num`` must be of type ``float``:

.. code-block:: python

def nums_below(numbers: Iterable[float], limit: float) -> List[float]:
def nums_below(numbers: Iterable[float], limit: float) -> list[float]:
output = []
for num in numbers:
if num < limit:
Expand All @@ -289,10 +312,13 @@ syntax like so:

.. code-block:: python

# If you're using Python 3.9+
my_global_dict: dict[int, float] = {}

# If you're using Python 3.6+
my_global_dict: Dict[int, float] = {}

# If you want compatibility with older versions of Python
# If you want compatibility with even older versions of Python
my_global_dict = {} # type: Dict[int, float]

.. _stubs-intro:
Expand Down
2 changes: 1 addition & 1 deletion docs/source/index.rst
Expand Up @@ -37,8 +37,8 @@ Mypy is a static type checker for Python 3 and Python 2.7.
class_basics
runtime_troubles
protocols
python2
dynamic_typing
python2
casts
duck_type_compatibility
stubs
Expand Down
42 changes: 21 additions & 21 deletions docs/source/kinds_of_types.rst
Expand Up @@ -241,27 +241,6 @@ more specific type:
since the caller may have to use :py:func:`isinstance` before doing anything
interesting with the value.

.. _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

from typing import List

t1: int | str # equivalent to Union[int, str]

t2: int | None # equivalent to Optional[int]

# Usable in type comments
t3 = 42 # type: int | str

.. _strict_optional:

Optional types and the None type
Expand Down Expand Up @@ -428,6 +407,27 @@ case you should add an explicit ``Optional[...]`` annotation (or type comment).
``Optional[...]`` type. It's possible that this will become the default
behavior in the future.

.. _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

from typing import List

t1: int | str # equivalent to Union[int, str]

t2: int | None # equivalent to Optional[int]

# Usable in type comments
t3 = 42 # type: int | str

.. _no_strict_optional:

Disabling strict optional checking
Expand Down
2 changes: 1 addition & 1 deletion docs/source/running_mypy.rst
Expand Up @@ -397,7 +397,7 @@ How mypy determines fully qualified module names depends on if the options
With :option:`--explicit-package-bases <mypy --explicit-package-bases>`, mypy
will locate the nearest parent directory that is a member of the ``MYPYPATH``
environment variable, the :confval:`mypy_path` config or is the current
working directory. mypy will then use the relative path to determine the
working directory. Mypy will then use the relative path to determine the
fully qualified module name.

For example, say your directory tree consists solely of
Expand Down