Skip to content

Commit 2d903e8

Browse files
Update type inference and annotations (#13736)
See #13681. Prefer mypy: ignore-errors over module level type: ignore, which is surprising. Fold starred expr section into talking about PEP 526 declaration only. Don't talk about stubs. Co-authored-by: Jelle Zijlstra <[email protected]>
1 parent 5f21936 commit 2d903e8

File tree

1 file changed

+71
-74
lines changed

1 file changed

+71
-74
lines changed

docs/source/type_inference_and_annotations.rst

Lines changed: 71 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,30 @@ Type inference and type annotations
66
Type inference
77
**************
88

9-
Mypy considers the initial assignment as the definition of a variable.
10-
If you do not explicitly
11-
specify the type of the variable, mypy infers the type based on the
12-
static type of the value expression:
9+
For most variables, if you do not explicitly specify its type, mypy will
10+
infer the correct type based on what is initially assigned to the variable.
1311

1412
.. code-block:: python
1513
16-
i = 1 # Infer type "int" for i
17-
l = [1, 2] # Infer type "list[int]" for l
14+
# Mypy will infer the type of these variables, despite no annotations
15+
i = 1
16+
reveal_type(i) # Revealed type is "builtins.int"
17+
l = [1, 2]
18+
reveal_type(l) # Revealed type is "builtins.list[builtins.int]"
1819
19-
Type inference is not used in dynamically typed functions (those
20-
without a function type annotation) — every local variable type defaults
21-
to ``Any`` in such functions. ``Any`` is discussed later in more detail.
20+
21+
.. note::
22+
23+
Note that mypy will not use type inference in dynamically typed functions
24+
(those without a function type annotation) — every local variable type
25+
defaults to ``Any`` in such functions. For more details, see :ref:`dynamic-typing`.
26+
27+
.. code-block:: python
28+
29+
def untyped_function():
30+
i = 1
31+
reveal_type(i) # Revealed type is "Any"
32+
# 'reveal_type' always outputs 'Any' in unchecked functions
2233
2334
.. _explicit-var-types:
2435

@@ -37,20 +48,33 @@ variable type annotation:
3748
Without the type annotation, the type of ``x`` would be just ``int``. We
3849
use an annotation to give it a more general type ``Union[int, str]`` (this
3950
type means that the value can be either an ``int`` or a ``str``).
40-
Mypy checks that the type of the initializer is compatible with the
41-
declared type. The following example is not valid, since the initializer is
42-
a floating point number, and this is incompatible with the declared
43-
type:
51+
52+
The best way to think about this is that the type annotation sets the type of
53+
the variable, not the type of the expression. For instance, mypy will complain
54+
about the following code:
4455

4556
.. code-block:: python
4657
47-
x: Union[int, str] = 1.1 # Error!
58+
x: Union[int, str] = 1.1 # error: Incompatible types in assignment
59+
# (expression has type "float", variable has type "Union[int, str]")
4860
4961
.. note::
5062

51-
The best way to think about this is that the type annotation sets the
52-
type of the variable, not the type of the expression. To force the
53-
type of an expression you can use :py:func:`cast(\<type\>, \<expression\>) <typing.cast>`.
63+
To explicitly override the type of an expression you can use
64+
:py:func:`cast(\<type\>, \<expression\>) <typing.cast>`.
65+
See :ref:`casts` for details.
66+
67+
Note that you can explicitly declare the type of a variable without
68+
giving it an initial value:
69+
70+
.. code-block:: python
71+
72+
# We only unpack two values, so there's no right-hand side value
73+
# for mypy to infer the type of "cs" from:
74+
a, b, *cs = 1, 2 # error: Need type annotation for "cs"
75+
76+
rs: list[int] # no assignment!
77+
p, q, *rs = 1, 2 # OK
5478
5579
Explicit types for collections
5680
******************************
@@ -69,15 +93,9 @@ In these cases you can give the type explicitly using a type annotation:
6993

7094
.. code-block:: python
7195
72-
l: list[int] = [] # Create empty list with type list[int]
96+
l: list[int] = [] # Create empty list of int
7397
d: dict[str, int] = {} # Create empty dictionary (str -> int)
7498
75-
Similarly, you can also give an explicit type when creating an empty set:
76-
77-
.. code-block:: python
78-
79-
s: set[int] = set()
80-
8199
.. note::
82100

83101
Using type arguments (e.g. ``list[int]``) on builtin collections like
@@ -90,13 +108,14 @@ Similarly, you can also give an explicit type when creating an empty set:
90108
Compatibility of container types
91109
********************************
92110

93-
The following program generates a mypy error, since ``list[int]``
94-
is not compatible with ``list[object]``:
111+
A quick note: container types can sometimes be unintuitive. We'll discuss this
112+
more in :ref:`variance`. For example, the following program generates a mypy error,
113+
because mypy treats ``list[int]`` as incompatible with ``list[object]``:
95114

96115
.. code-block:: python
97116
98117
def f(l: list[object], k: list[int]) -> None:
99-
l = k # Type check error: incompatible types in assignment
118+
l = k # error: Incompatible types in assignment
100119
101120
The reason why the above assignment is disallowed is that allowing the
102121
assignment could result in non-int values stored in a list of ``int``:
@@ -108,33 +127,32 @@ assignment could result in non-int values stored in a list of ``int``:
108127
l.append('x')
109128
print(k[-1]) # Ouch; a string in list[int]
110129
111-
Other container types like :py:class:`dict` and :py:class:`set` behave similarly. We
112-
will discuss how you can work around this in :ref:`variance`.
130+
Other container types like :py:class:`dict` and :py:class:`set` behave similarly.
113131

114-
You can still run the above program; it prints ``x``. This illustrates
115-
the fact that static types are used during type checking, but they do
116-
not affect the runtime behavior of programs. You can run programs with
117-
type check failures, which is often very handy when performing a large
118-
refactoring. Thus you can always 'work around' the type system, and it
132+
You can still run the above program; it prints ``x``. This illustrates the fact
133+
that static types do not affect the runtime behavior of programs. You can run
134+
programs with type check failures, which is often very handy when performing a
135+
large refactoring. Thus you can always 'work around' the type system, and it
119136
doesn't really limit what you can do in your program.
120137

121138
Context in type inference
122139
*************************
123140

124-
Type inference is *bidirectional* and takes context into account. For
125-
example, the following is valid:
141+
Type inference is *bidirectional* and takes context into account.
142+
143+
Mypy will take into account the type of the variable on the left-hand side
144+
of an assignment when inferring the type of the expression on the right-hand
145+
side. For example, the following will type check:
126146

127147
.. code-block:: python
128148
129149
def f(l: list[object]) -> None:
130150
l = [1, 2] # Infer type list[object] for [1, 2], not list[int]
131151
132-
In an assignment, the type context is determined by the assignment
133-
target. In this case this is ``l``, which has the type
134-
``list[object]``. The value expression ``[1, 2]`` is type checked in
135-
this context and given the type ``list[object]``. In the previous
136-
example we introduced a new variable ``l``, and here the type context
137-
was empty.
152+
153+
The value expression ``[1, 2]`` is type checked with the additional
154+
context that it is being assigned to a variable of type ``list[object]``.
155+
This is used to infer the type of the *expression* as ``list[object]``.
138156

139157
Declared argument types are also used for type context. In this program
140158
mypy knows that the empty list ``[]`` should have type ``list[int]`` based
@@ -167,51 +185,30 @@ Working around the issue is easy by adding a type annotation:
167185
a: list[int] = [] # OK
168186
foo(a)
169187
170-
Starred expressions
171-
*******************
172-
173-
In most cases, mypy can infer the type of starred expressions from the
174-
right-hand side of an assignment, but not always:
175-
176-
.. code-block:: python
177-
178-
a, *bs = 1, 2, 3 # OK
179-
p, q, *rs = 1, 2 # Error: Type of rs cannot be inferred
180-
181-
On first line, the type of ``bs`` is inferred to be
182-
``list[int]``. However, on the second line, mypy cannot infer the type
183-
of ``rs``, because there is no right-hand side value for ``rs`` to
184-
infer the type from. In cases like these, the starred expression needs
185-
to be annotated with a starred type:
186-
187-
.. code-block:: python
188-
189-
p, q, *rs = 1, 2 # type: int, int, list[int]
190-
191-
Here, the type of ``rs`` is set to ``list[int]``.
192-
193188
Silencing type errors
194189
*********************
195190

196191
You might want to disable type checking on specific lines, or within specific
197192
files in your codebase. To do that, you can use a ``# type: ignore`` comment.
198193

199-
For example, say that the web framework that you use now takes an integer
200-
argument to ``run()``, which starts it on localhost on that port. Like so:
194+
For example, say in its latest update, the web framework you use can now take an
195+
integer argument to ``run()``, which starts it on localhost on that port.
196+
Like so:
201197

202198
.. code-block:: python
203199
204200
# Starting app on http://localhost:8000
205201
app.run(8000)
206202
207-
However, the type stubs that the package uses is not up-to-date, and it still
208-
expects only ``str`` types for ``run()``. This would give you the following error:
203+
However, the devs forgot to update their type annotations for
204+
``run``, so mypy still thinks ``run`` only expects ``str`` types.
205+
This would give you the following error:
209206

210207
.. code-block:: text
211208
212209
error: Argument 1 to "run" of "A" has incompatible type "int"; expected "str"
213210
214-
If you cannot directly fix the type stubs yourself, you can temporarily
211+
If you cannot directly fix the web framework yourself, you can temporarily
215212
disable type checking on that line, by adding a ``# type: ignore``:
216213

217214
.. code-block:: python
@@ -229,7 +226,7 @@ short explanation of the bug. To do that, use this format:
229226
.. code-block:: python
230227
231228
# Starting app on http://localhost:8000
232-
app.run(8000) # type: ignore # `run()` now accepts an `int`, as a port
229+
app.run(8000) # type: ignore # `run()` in v2.0 accepts an `int`, as a port
233230
234231
235232
Mypy displays an error code for each error if you use
@@ -244,12 +241,12 @@ It is possible to add a specific error-code in your ignore comment (e.g.
244241
``# type: ignore[attr-defined]``) to clarify what's being silenced. You can
245242
find more information about error codes :ref:`here <silence-error-codes>`.
246243

247-
Similarly, you can also ignore all mypy checks in a file, by adding a
248-
``# type: ignore`` at the top of the file:
244+
Similarly, you can also ignore all mypy errors in a file, by adding a
245+
``# mypy: ignore-errors`` at the top of the file:
249246

250247
.. code-block:: python
251248
252-
# type: ignore
249+
# mypy: ignore-errors
253250
# This is a test file, skipping type checking in it.
254251
import unittest
255252
...

0 commit comments

Comments
 (0)