8000 Update cheat sheet docs (#13679) · python/mypy@e4edea3 · GitHub
[go: up one dir, main page]

Skip to content

Commit e4edea3

Browse files
authored
Update cheat sheet docs (#13679)
See #13681
1 parent 1d4395f commit e4edea3

File tree

2 files changed

+65
-61
lines changed

2 files changed

+65
-61
lines changed

docs/source/cheat_sheet_py3.rst

Lines changed: 63 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,42 @@
11
.. _cheat-sheet-py3:
22

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+
======================
155

6+
This document is a quick cheat sheet showing how to use type
7+
annotations for various common types in Python.
168

179
Variables
1810
*********
1911

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.
2215

2316
.. code-block:: python
2417
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
2619
age: int = 1
2720
2821
# You don't need to initialize a variable to annotate it
2922
a: int # Ok (no value at runtime until assigned)
3023
31-
# The latter is useful in conditional branches
24+
# Doing so is useful in conditional branches
3225
child: bool
3326
if age < 18:
3427
child = True
3528
else:
3629
child = False
3730
3831
39-
Built-in types
40-
**************
32+
Useful built-in types
33+
*********************
4134

4235
.. code-block:: python
4336
44-
4537
from typing import List, Set, Dict, Tuple, Optional
4638
47-
# For simple built-in types, just use the name of the type
39+
# For most types, just use the name of the type
4840
x: int = 1
4941
x: float = 1.0
5042
8000 x: bool = True
@@ -85,8 +77,6 @@ Built-in types
8577
Functions
8678
*********
8779

88-
Python 3 supports an annotation syntax for function declarations.
89-
9080
.. code-block:: python
9181
9282
from typing import Callable, Iterator, Union, Optional
@@ -124,73 +114,69 @@ Python 3 supports an annotation syntax for function declarations.
124114
) -> bool:
125115
...
126116
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:
130121
pass
131122
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)
134133
135134
When you're puzzled or when things are complicated
136135
**************************************************
137136

138137
.. code-block:: python
139138
140-
from typing import Union, Any, Optional, cast
139+
from typing import Union, Any, Optional, TYPE_CHECKING, cast
141140
142141
# To find out what type mypy infers for an expression anywhere in
143142
# your program, wrap it in reveal_type(). Mypy will print an error
144143
# 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"
146145
147146
# Use Union when something could be one of a few types
148147
x: list[Union[int, str]] = [3, 5, "test", "fun"]
149148
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-
154149
# 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
156151
x: list[str] = []
157152
x: Optional[str] = None
158153
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()
163157
164158
# Use a "type: ignore" comment to suppress errors on a given line,
165159
# 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 ...
169162
170163
# "cast" is a helper function that lets you override the inferred
171164
# type of an expression. It's only for mypy -- there's no runtime check.
172165
a = [4]
173166
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
193177
178+
In some cases type annotations can cause issues at runtime, see
179+
:ref:`runtime_troubles` for dealing with this.
194180

195181
Standard "duck types"
196182
*********************
@@ -216,7 +202,7 @@ that are common in idiomatic Python are standardized.
216202
# Mapping describes a dict-like object (with "__getitem__") that we won't
217203
# mutate, and MutableMapping one (with "__setitem__") that we might
218204
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...
220206
return list(my_mapping.keys())
221207
222208
f({3: 'yes', 4: 'no'})
@@ -263,6 +249,22 @@ Classes
263249
def __init__(self) -> None:
264250
self.items: list[str] = []
265251
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+
266268
267269
Coroutines and asyncio
268270
**********************

docs/source/type_inference_and_annotations.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.. _type-inference-and-annotations:
2+
13
Type inference and type annotations
24
===================================
35

0 commit comments

Comments
 (0)
0