You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/source/type_narrowing.rst
+37-5Lines changed: 37 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,7 +3,7 @@
3
3
Type narrowing
4
4
==============
5
5
6
-
This section is dedicated to several type narrowing
6
+
This section is dedicated to several type narrowing
7
7
techniques which are supported by mypy.
8
8
9
9
Type narrowing is when you convince a type checker that a broader type is actually more specific, for instance, that an object of type ``Shape`` is actually of the narrower type ``Square``.
@@ -14,10 +14,11 @@ Type narrowing expressions
14
14
15
15
The simplest way to narrow a type is to use one of the supported expressions:
16
16
17
-
- :py:func:`isinstance` like in ``isinstance(obj, float)`` will narrow ``obj`` to have ``float`` type
18
-
- :py:func:`issubclass` like in ``issubclass(cls, MyClass)`` will narrow ``cls`` to be ``Type[MyClass]``
19
-
- :py:class:`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
17
+
- :py:func:`isinstance` like in :code:`isinstance(obj, float)` will narrow ``obj`` to have ``float`` type
18
+
- :py:func:`issubclass` like in :code:`issubclass(cls, MyClass)` will narrow ``cls`` to be ``Type[MyClass]``
19
+
- :py:class:`type` like in :code:`type(obj) is int` will narrow ``obj`` to have ``int`` type
20
+
- :py:func:`callable` like in :code:`callable(obj)` will narrow object to callable type
21
+
- :code:`obj is not None` will narrow object to its :ref:`non-optional form <strict_optional>`
21
22
22
23
Type narrowing is contextual. For example, based on the condition, mypy will narrow an expression only within an ``if`` branch:
23
24
@@ -83,6 +84,7 @@ We can also use ``assert`` to narrow types in the same context:
83
84
reveal_type(x) # Revealed type is "builtins.int"
84
85
print(x +'!') # Typechecks with `mypy`, but fails in runtime.
85
86
87
+
86
88
issubclass
87
89
~~~~~~~~~~
88
90
@@ -359,3 +361,33 @@ What happens here?
359
361
.. note::
360
362
361
363
The same will work with ``isinstance(x := a, float)`` as well.
364
+
365
+
Limitations
366
+
-----------
367
+
368
+
Mypy's analysis is limited to individual symbols and it will not track
369
+
relationships between symbols. For example, in the following code
370
+
it's easy to deduce that if :code:`a` is None then :code:`b` must not be,
371
+
therefore :code:`a or b` will always be a string, but Mypy will not be able to tell that:
372
+
373
+
.. code-block:: python
374
+
375
+
deff(a: str|None, b: str|None) -> str:
376
+
if a isnotNoneor b isnotNone:
377
+
return a or b # Incompatible return value type (got "str | None", expected "str")
378
+
return'spam'
379
+
380
+
Tracking these sort of cross-variable conditions in a type checker would add significant complexity
381
+
and performance overhead.
382
+
383
+
You can use an ``assert`` to convince the type checker, override it with a :ref:`cast <casts>`
384
+
or rewrite the function to be slightly more verbose:
0 commit comments