1
1
.. _cheat-sheet-py3 :
2
2
3
- Type hints cheat sheet (Python 3)
4
- =================================
5
-
6
- This document is a quick cheat sheet showing how the :pep: `484 ` type
7
- annotation notation represents various common types in Python 3.
8
-
9
- .. note ::
10
-
11
- Technically many of the type annotations shown below are redundant,
12
- because mypy can derive them from the type of the expression. So
13
- many of the examples have a dual purpose: show how to write the
14
- annotation, and show the inferred types.
3
+ Type hints cheat sheet
4
+ ======================
15
5
6
+ This document is a quick cheat sheet showing how to use type
7
+ annotations for various common types in Python.
16
8
17
9
Variables
18
10
*********
19
11
20
- Python 3.6 introduced a syntax for annotating variables in :pep: `526 `
21
- and we use it in most examples.
12
+ Technically many of the type annotations shown below are redundant,
13
+ since mypy can usually infer the type of a variable from its value.
14
+ See :ref: `type-inference-and-annotations ` for more details.
22
15
23
16
.. code-block :: python
24
17
25
- # This is how you declare the type of a variable type in Python 3.6
18
+ # This is how you declare the type of a variable
26
19
age: int = 1
27
20
28
21
# You don't need to initialize a variable to annotate it
29
22
a: int # Ok (no value at runtime until assigned)
30
23
31
- # The latter is useful in conditional branches
24
+ # Doing so is useful in conditional branches
32
25
child: bool
33
26
if age < 18 :
34
27
child = True
35
28
else :
36
29
child = False
37
30
38
31
39
- Built -in types
40
- **************
32
+ Useful built -in types
33
+ *********************
41
34
42
35
.. code-block :: python
43
36
44
-
45
37
from typing import List, Set, Dict, Tuple, Optional
46
38
47
- # For simple built-in types, just use the name of the type
39
+ # For most types, just use the name of the type
48
40
x: int = 1
49
41
x: float = 1.0
50
42
8000
x: bool = True
@@ -85,8 +77,6 @@ Built-in types
85
77
Functions
86
78
*********
87
79
88
- Python 3 supports an annotation syntax for function declarations.
89
-
90
80
.. code-block :: python
91
81
92
82
from typing import Callable, Iterator, Union, Optional
@@ -124,73 +114,69 @@ Python 3 supports an annotation syntax for function declarations.
124
114
) -> bool :
125
115
...
126
116
127
- # An argument can be declared positional-only by giving it a name
128
- # starting with two underscores:
129
- def quux (__x : int ) -> None :
117
+ # Mypy understands positional-only and keyword-only arguments
118
+ # Positional-only arguments can also be marked by using a name starting with
119
+ # two underscores
120
+ def quux (x : int , / * , y : int ) -> None :
130
121
pass
131
122
132
- quux(3 ) # Fine
133
- quux(__x = 3 ) # Error
123
+ quux(3 , y = 5 ) # Ok
124
+ quux(3 , 5 ) # error: Too many positional arguments for "quux"
125
+ quux(x = 3 , y = 5 ) # error: Unexpected keyword argument "x" for "quux"
126
+
127
+ # This makes each positional arg and each keyword arg a "str"
128
+ def call (self , * args : str , ** kwargs : str ) -> str :
129
+ reveal_type(args) # Revealed type is "tuple[str, ...]"
130
+ reveal_type(kwargs) # Revealed type is "dict[str, str]"
131
+ request = make_request(* args, ** kwargs)
132
+ return self .do_api_query(request)
134
133
135
134
When you're puzzled or when things are complicated
136
135
**************************************************
137
136
138
137
.. code-block :: python
139
138
140
- from typing import Union, Any, Optional, cast
139
+ from typing import Union, Any, Optional, TYPE_CHECKING , cast
141
140
142
141
# To find out what type mypy infers for an expression anywhere in
143
142
# your program, wrap it in reveal_type(). Mypy will print an error
144
143
# message with the type; remove it again before running the code.
145
- reveal_type(1 ) # -> Revealed type is "builtins.int"
144
+ reveal_type(1 ) # Revealed type is "builtins.int"
146
145
147
146
# Use Union when something could be one of a few types
148
147
x: list[Union[int , str ]] = [3 , 5 , " test" , " fun" ]
149
148
150
- # Use Any if you don't know the type of something or it's too
151
- # dynamic to write a type for
152
- x: Any = mystery_function()
153
-
154
149
# If you initialize a variable with an empty container or "None"
155
- # you may have to help mypy a bit by providing a type annotation
150
+ # you may have to help mypy a bit by providing an explicit type annotation
156
151
x: list[str ] = []
157
152
x: Optional[str ] = None
158
153
159
- # This makes each positional arg and each keyword arg a "str"
160
- def call (self , * args : str , ** kwargs : str ) -> str :
161
- request = make_request(* args, ** kwargs)
162
- return self .do_api_query(request)
154
+ # Use Any if you don't know the type of something or it's too
155
+ # dynamic to write a type for
156
+ x: Any = mystery_function()
163
157
164
158
# Use a "type: ignore" comment to suppress errors on a given line,
165
159
# when your code confuses mypy or runs into an outright bug in mypy.
166
- # Good practice is to comment every "ignore" with a bug link
167
- # (in mypy, typeshed, or your own code) or an explanation of the issue.
168
- x = confusing_function() # type: ignore # https://github.com/python/mypy/issues/1167
160
+ # Good practice is to add a comment explaining the issue.
161
+ x = confusing_function() # type: ignore # confusing_function won't return None here because ...
169
162
170
163
# "cast" is a helper function that lets you override the inferred
171
164
# type of an expression. It's only for mypy -- there's no runtime check.
172
165
a = [4 ]
173
166
b = cast(list[int ], a) # Passes fine
174
- c = cast(list[str ], a) # Passes fine (no runtime check)
175
- reveal_type(c) # -> Revealed type is "builtins.list[builtins.str]"
176
- print (c) # -> [4]; the object is not cast
177
-
178
- # If you want dynamic attributes on your class, have it override "__setattr__"
179
- # or "__getattr__" in a stub or in your source code.
180
- #
181
- # "__setattr__" allows for dynamic assignment to names
182
- # "__getattr__" allows for dynamic access to names
183
- class A :
184
- # This will allow assignment to any A.x, if x is the same type as "value"
185
- # (use "value: Any" to allow arbitrary types)
186
- def __setattr__ (self , name : str , value : int ) -> None : ...
187
-
188
- # This will allow access to any A.x, if x is compatible with the return type
189
- def __getattr__ (self , name : str ) -> int : ...
190
-
191
- a.foo = 42 # Works
192
- a.bar = ' Ex-parrot' # Fails type checking
167
+ c = cast(list[str ], a) # Passes fine despite being a lie (no runtime check)
168
+ reveal_type(c) # Revealed type is "builtins.list[builtins.str]"
169
+ print (c) # Still prints [4] ... the object is not changed or casted at runtime
170
+
171
+ # Use "TYPE_CHECKING" if you want to have code that mypy can see but will not
172
+ # be executed at runtime (or to have code that mypy can't see)
173
+ if TYPE_CHECKING :
174
+ import json
175
+ else :
176
+ import orjson as json # mypy is unaware of this
193
177
178
+ In some cases type annotations can cause issues at runtime, see
179
+ :ref: `runtime_troubles ` for dealing with this.
194
180
195
181
Standard "duck types"
196
182
*********************
@@ -216,7 +202,7 @@ that are common in idiomatic Python are standardized.
216
202
# Mapping describes a dict-like object (with "__getitem__") that we won't
217
203
# mutate, and MutableMapping one (with "__setitem__") that we might
218
204
def f (my_mapping : Mapping[int , str ]) -> list[int ]:
219
- my_mapping[5 ] = ' maybe' # if we try this, mypy will throw an error ...
205
+ my_mapping[5 ] = ' maybe' # mypy will complain about this line ...
220
206
return list (my_mapping.keys())
221
207
222
208
f({3 : ' yes' , 4 : ' no' })
@@ -263,6 +249,22 @@ Classes
263
249
def __init__ (self ) -> None :
264
250
self .items: list[str ] = []
265
251
252
+ # If you want dynamic attributes on your class, have it override "__setattr__"
253
+ # or "__getattr__" in a stub or in your source code.
254
+ #
255
+ # "__setattr__" allows for dynamic assignment to names
256
+ # "__getattr__" allows for dynamic access to names
257
+ class A :
258
+ # This will allow assignment to any A.x, if x is the same type as "value"
259
+ # (use "value: Any" to allow arbitrary types)
260
+ def __setattr__ (self , name : str , value : int ) -> None : ...
261
+
262
+ # This will allow access to any A.x, if x is compatible with the return type
263
+ def __getattr__ (self , name : str ) -> int : ...
264
+
265
+ a.foo = 42 # Works
266
+ a.bar = ' Ex-parrot' # Fails type checking
267
+
266
268
267
269
Coroutines and asyncio
268
270
**********************
0 commit comments