Skip to content

Commit ab62307

Browse files
sobolevnIvan Levkivskyi
authored and
Ivan Levkivskyi
committed
Add type narrowing docs about callable (#11174)
Closes #11172
1 parent b1084ab commit ab62307

File tree

1 file changed

+51
-17
lines changed

1 file changed

+51
-17
lines changed

docs/source/type_narrowing.rst

+51-17
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ The simplest way to narrow a type is to use one of the supported expressions:
1717
- :py:func:`isinstance` like in ``isinstance(obj, float)`` will narrow ``obj`` to have ``float`` type
1818
- :py:func:`issubclass` like in ``issubclass(cls, MyClass)`` will narrow ``cls`` to be ``Type[MyClass]``
1919
- :py:func:`type` like in ``type(obj) is int`` will narrow ``obj`` to have ``int`` type
20+
- :py:func:`callable` like in ``callable(obj)`` will narrow object to callable type
2021

2122
Type narrowing is contextual. For example, based on the condition, mypy will narrow an expression only within an ``if`` branch:
2223

@@ -57,6 +58,34 @@ We can also use ``assert`` to narrow types in the same context:
5758
assert isinstance(arg, int)
5859
reveal_type(arg) # Revealed type: "builtins.int"
5960
61+
.. note::
62+
63+
With :option:`--warn-unreachable <mypy --warn-unreachable>`
64+
narrowing types to some impossible state will be treated as an error.
65+
66+
.. code-block:: python
67+
68+
def function(arg: int):
69+
# error: Subclass of "int" and "str" cannot exist:
70+
# would have incompatible method signatures
71+
assert isinstance(arg, str)
72+
73+
# error: Statement is unreachable
74+
print("so mypy concludes the assert will always trigger")
75+
76+
Without ``--warn-unreachable`` mypy will simply not check code it deems to be
77+
unreachable. See :ref:`unreachable` for more information.
78+
79+
.. code-block:: python
80+
81+
x: int = 1
82+
assert isinstance(x, str)
83+
reveal_type(x) # Revealed type is "builtins.int"
84+
print(x + '!') # Typechecks with `mypy`, but fails in runtime.
85+
86+
issubclass
87+
~~~~~~~~~~
88+
6089
Mypy can also use :py:func:`issubclass`
6190
for better type inference when working with types and metaclasses:
6291

@@ -75,31 +104,36 @@ for better type inference when working with types and metaclasses:
75104
reveal_type(t) # Revealed type is "Type[MyCalcMeta]"
76105
t.calc() # Okay
77106
78-
.. note::
107+
callable
108+
~~~~~~~~
79109

80-
With :option:`--warn-unreachable <mypy --warn-unreachable>`
81-
narrowing types to some impossible state will be treated as an error.
110+
Mypy knows what types are callable and which ones are not during type checking.
111+
So, we know what ``callable()`` will return. For example:
82112

83-
.. code-block:: python
113+
.. code-block:: python
84114
85-
def function(arg: int):
86-
# error: Subclass of "int" and "str" cannot exist:
87-
# would have incompatible method signatures
88-
assert isinstance(arg, str)
115+
from typing import Callable
89116
90-
# error: Statement is unreachable
91-
print("so mypy concludes the assert will always trigger")
117+
x: Callable[[], int]
92118
93-
Without ``--warn-unreachable`` mypy will simply not check code it deems to be
94-
unreachable. See :ref:`unreachable` for more information.
119+
if callable(x):
120+
reveal_type(x) # N: Revealed type is "def () -> builtins.int"
121+
else:
122+
... # Will never be executed and will raise error with `--warn-unreachable`
95123
96-
.. code-block:: python
124+
``callable`` function can even split ``Union`` type
125+
for callable and non-callable parts:
97126

98-
x: int = 1
99-
assert isinstance(x, str)
100-
reveal_type(x) # Revealed type is "builtins.int"
101-
print(x + '!') # Typechecks with `mypy`, but fails in runtime.
127+
.. code-block:: python
128+
129+
from typing import Callable, Union
130+
131+
x: Union[int, Callable[[], int]]
102132
133+
if callable(x):
134+
reveal_type(x) # N: Revealed type is "def () -> builtins.int"
135+
else:
136+
reveal_type(x) # N: Revealed type is "builtins.int"
103137
104138
.. _casts:
105139

0 commit comments

Comments
 (0)