Skip to content

Docs: adds a note about issubclass usage in common_issues.rst #11014

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 3 commits into from
Sep 4, 2021
Merged
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.
Loading
Diff view
Diff view
56 changes: 33 additions & 23 deletions docs/source/common_issues.rst
Original file line number Diff line number Diff line change
Expand Up @@ -367,19 +367,38 @@ above example:
Complex type tests
------------------

Mypy can usually infer the types correctly when using :py:func:`isinstance <isinstance>`
type tests, but for other kinds of checks you may need to add an
Mypy can usually infer the types correctly when using :py:func:`isinstance <isinstance>`,
:py:func:`issubclass <issubclass>`,
or ``type(obj) is some_class`` type tests,
and even user-defined type guards,
Copy link
Member Author

Choose a reason for hiding this comment

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

I will add a link here as well in the next PR

but for other kinds of checks you may need to add an
explicit type cast:

.. code-block:: python

def f(o: object) -> None:
if type(o) is int:
o = cast(int, o)
g(o + 1) # This would be an error without the cast
...
else:
...
from typing import Sequence, cast

def find_first_str(a: Sequence[object]) -> str:
index = next((i for i, s in enumerate(a) if isinstance(s, str)), -1)
if index < 0:
raise ValueError('No str found')

found = a[index] # Has `object` type, despite the fact that we know it is `str`
return cast(str, found) # So, we need an explicit cast to make mypy happy

Alternatively, you can use ``assert`` statement together with some
of the supported type inference techniques:

.. code-block:: python

def find_first_str(a: Sequence[object]) -> str:
index = next((i for i, s in enumerate(a) if isinstance(s, str)), -1)
if index < 0:
raise ValueError('No str found')

found = a[index] # Has `object` type, despite the fact that we know it is `str`
assert isinstance(found, str) # Now, `found` will be narrowed to `str` subtype
return found # No need for the explicit `cast()` anymore

.. note::

Expand All @@ -390,19 +409,11 @@ explicit type cast:
runtime. The cast above would have been unnecessary if the type of
``o`` was ``Any``.

Mypy can't infer the type of ``o`` after the :py:class:`type() <type>` check
because it only knows about :py:func:`isinstance` (and the latter is better
style anyway). We can write the above code without a cast by using
:py:func:`isinstance`:
.. note::

.. code-block:: python
You can read more about type narrowing techniques here.
Copy link
Member Author

Choose a reason for hiding this comment

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

I will add a link to the new page here in the next PR


def f(o: object) -> None:
if isinstance(o, int): # Mypy understands isinstance checks
g(o + 1) # Okay; type of o is inferred as int here
...

Type inference in mypy is designed to work well in common cases, to be
Type inference in Mypy is designed to work well in common cases, to be
predictable and to let the type checker give useful error
messages. More powerful type inference strategies often have complex
and difficult-to-predict failure modes and could result in very
Expand Down Expand Up @@ -621,7 +632,7 @@ You can install the latest development version of mypy from source. Clone the
sudo python3 -m pip install --upgrade .

Variables vs type aliases
-----------------------------------
-------------------------

Mypy has both type aliases and variables with types like ``Type[...]`` and it is important to know their difference.

Expand Down Expand Up @@ -662,7 +673,7 @@ Mypy has both type aliases and variables with types like ``Type[...]`` and it is
def fun2(x: tp) -> None: ... # error: Variable "__main__.tp" is not valid as a type

Incompatible overrides
------------------------------
----------------------

It's unsafe to override a method with a more specific argument type,
as it violates the `Liskov substitution principle
Expand Down Expand Up @@ -773,7 +784,6 @@ False:
If you use the :option:`--warn-unreachable <mypy --warn-unreachable>` flag, mypy will generate
an error about each unreachable code block.


Narrowing and inner functions
-----------------------------

Expand Down