Skip to content

Commit 4ccfca1

Browse files
authored
Improve cheat sheet (#13873)
- Mention PEP 604 unions - Separate out the 3.8 stuff to keep things more readable - Remove mention of typing.Match - Remove unnecessary mention of stub - Make classes more prominent - Clarify that forward references fail at runtime - More of an example for Any - Mention None return - Make default value example mean something - Move Union docs to builtin types Linking #13681
1 parent 045ea8c commit 4ccfca1

File tree

1 file changed

+76
-76
lines changed

1 file changed

+76
-76
lines changed

docs/source/cheat_sheet_py3.rst

Lines changed: 76 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -34,39 +34,45 @@ Useful built-in types
3434

3535
.. code-block:: python
3636
37-
from typing import List, Set, Dict, Tuple, Optional
38-
3937
# For most types, just use the name of the type
4038
x: int = 1
4139
x: float = 1.0
4240
x: bool = True
4341
x: str = "test"
4442
x: bytes = b"test"
4543
46-
# For collections, the type of the collection item is in brackets
47-
# (Python 3.9+)
44+
# For collections on Python 3.9+, the type of the collection item is in brackets
4845
x: list[int] = [1]
4946
x: set[int] = {6, 7}
5047
51-
# In Python 3.8 and earlier, the name of the collection type is
52-
# capitalized, and the type is imported from the 'typing' module
53-
x: List[int] = [1]
54-
x: Set[int] = {6, 7}
55-
5648
# For mappings, we need the types of both keys and values
5749
x: dict[str, float] = {"field": 2.0} # Python 3.9+
58-
x: Dict[str, float] = {"field": 2.0}
5950
6051
# For tuples of fixed size, we specify the types of all the elements
6152
x: tuple[int, str, float] = (3, "yes", 7.5) # Python 3.9+
62-
x: Tuple[int, str, float] = (3, "yes", 7.5)
6353
6454
# For tuples of variable size, we use one type and ellipsis
6555
x: tuple[int, ...] = (1, 2, 3) # Python 3.9+
56+
57+
# On Python 3.8 and earlier, the name of the collection type is
58+
# capitalized, and the type is imported from the 'typing' module
59+
from typing import List, Set, Dict, Tuple
60+
x: List[int] = [1]
61+
x: Set[int] = {6, 7}
62+
x: Dict[str, float] = {"field": 2.0}
63+
x: Tuple[int, str, float] = (3, "yes", 7.5)
6664
x: Tuple[int, ...] = (1, 2, 3)
6765
68-
# Use Optional[] for values that could be None
69-
x: Optional[str] = some_function()
66+
from typing import Union, Optional
67+
68+
# On Python 3.10+, use the | operator when something could be one of a few types
69+
x: list[int | str] = [3, 5, "test", "fun"] # Python 3.10+
70+
# On earlier versions, use Union
71+
x: list[Union[int, str]] = [3, 5, "test", "fun"]
72+
73+
# Use Optional[X] for a value that could be None
74+
# Optional[X] is the same as X | None or Union[X, None]
75+
x: Optional[str] = "something" if some_condition() else None
7076
# Mypy understands a value can't be None in an if-statement
7177
if x is not None:
7278
print(x.upper())
@@ -89,9 +95,10 @@ Functions
8995
def plus(num1: int, num2: int) -> int:
9096
return num1 + num2
9197
92-
# Add default value for an argument after the type annotation
93-
def f(num1: int, my_float: float = 3.5) -> float:
94-
return num1 + my_float
98+
# If a function does not return a value, use None as the return type
99+
# Default value for an argument goes after the type annotation
100+
def show(value: str, excitement: int = 10) -> None:
101+
print(value + "!" * excitement)
95102
96103
# This is how you annotate a callable (function) value
97104
x: Callable[[int, float], float] = f
@@ -124,13 +131,61 @@ Functions
124131
quux(3, 5) # error: Too many positional arguments for "quux"
125132
quux(x=3, y=5) # error: Unexpected keyword argument "x" for "quux"
126133
127-
# This makes each positional arg and each keyword arg a "str"
134+
# This says each positional arg and each keyword arg is a "str"
128135
def call(self, *args: str, **kwargs: str) -> str:
129136
reveal_type(args) # Revealed type is "tuple[str, ...]"
130137
reveal_type(kwargs) # Revealed type is "dict[str, str]"
131138
request = make_request(*args, **kwargs)
132139
return self.do_api_query(request)
133140
141+
Classes
142+
*******
143+
144+
.. code-block:: python
145+
146+
class MyClass:
147+
# You can optionally declare instance variables in the class body
148+
attr: int
149+
# This is an instance variable with a default value
150+
charge_percent: int = 100
151+
152+
# The "__init__" method doesn't return anything, so it gets return
153+
# type "None" just like any other method that doesn't return anything
154+
def __init__(self) -> None:
155+
...
156+
157+
# For instance methods, omit type for "self"
158+
def my_method(self, num: int, str1: str) -> str:
159+
return num * str1
160+
161+
# User-defined classes are valid as types in annotations
162+
x: MyClass = MyClass()
163+
164+
# You can also declare the type of an attribute in "__init__"
165+
class Box:
166+
def __init__(self) -> None:
167+
self.items: list[str] = []
168+
169+
# You can use the ClassVar annotation to declare a class variable
170+
class Car:
171+
seats: ClassVar[int] = 4
172+
passengers: ClassVar[list[str]]
173+
174+
# If you want dynamic attributes on your class, have it
175+
# override "__setattr__" or "__getattr__":
176+
# - "__getattr__" allows for dynamic access to names
177+
# - "__setattr__" allows for dynamic assignment to names
178+
class A:
179+
# This will allow assignment to any A.x, if x is the same type as "value"
180+
# (use "value: Any" to allow arbitrary types)
181+
def __setattr__(self, name: str, value: int) -> None: ...
182+
183+
# This will allow access to any A.x, if x is compatible with the return type
184+
def __getattr__(self, name: str) -> int: ...
185+
186+
a.foo = 42 # Works
187+
a.bar = 'Ex-parrot' # Fails type checking
188+
134189
When you're puzzled or when things are complicated
135190
**************************************************
136191

@@ -143,9 +198,6 @@ When you're puzzled or when things are complicated
143198
# message with the type; remove it again before running the code.
144199
reveal_type(1) # Revealed type is "builtins.int"
145200
146-
# Use Union when something could be one of a few types
147-
x: list[Union[int, str]] = [3, 5, "test", "fun"]
148-
149201
# If you initialize a variable with an empty container or "None"
150202
# you may have to help mypy a bit by providing an explicit type annotation
151203
x: list[str] = []
@@ -154,6 +206,8 @@ When you're puzzled or when things are complicated
154206
# Use Any if you don't know the type of something or it's too
155207
# dynamic to write a type for
156208
x: Any = mystery_function()
209+
# Mypy will let you do anything with x!
210+
x.whatever() * x["you"] + x("want") - any(x) and all(x) is super # no errors
157211
158212
# Use a "type: ignore" comment to suppress errors on a given line,
159213
# when your code confuses mypy or runs into an outright bug in mypy.
@@ -216,56 +270,6 @@ that are common in idiomatic Python are standardized.
216270
217271
You can even make your own duck types using :ref:`protocol-types`.
218272

219-
Classes
220-
*******
221-
222-
.. code-block:: python
223-
224-
class MyClass:
225-
# You can optionally declare instance variables in the class body
226-
attr: int
227-
# This is an instance variable with a default value
228-
charge_percent: int = 100
229-
230-
# The "__init__" method doesn't return anything, so it gets return
231-
# type "None" just like any other method that doesn't return anything
232-
def __init__(self) -> None:
233-
...
234-
235-
# For instance methods, omit type for "self"
236-
def my_method(self, num: int, str1: str) -> str:
237-
return num * str1
238-
239-
# User-defined classes are valid as types in annotations
240-
x: MyClass = MyClass()
241-
242-
# You can use the ClassVar annotation to declare a class variable
243-
class Car:
244-
seats: ClassVar[int] = 4
245-
passengers: ClassVar[list[str]]
246-
247-
# You can also declare the type of an attribute in "__init__"
248-
class Box:
249-
def __init__(self) -> None:
250-
self.items: list[str] = []
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-
268-
269273
Coroutines and asyncio
270274
**********************
271275

@@ -290,11 +294,7 @@ Miscellaneous
290294
.. code-block:: python
291295
292296
import sys
293-
import re
294-
from typing import Match, IO
295-
296-
# "typing.Match" describes regex matches from the re module
297-
x: Match[str] = re.match(r'[0-9]+', "15")
297+
from typing import IO
298298
299299
# Use IO[] for functions that should accept or return any
300300
# object that comes from an open() call (IO[] does not
@@ -309,7 +309,7 @@ Miscellaneous
309309
310310
# Forward references are useful if you want to reference a class before
311311
# it is defined
312-
def f(foo: A) -> int: # This will fail
312+
def f(foo: A) -> int: # This will fail at runtime with 'A' is not defined
313313
...
314314
315315
class A:

0 commit comments

Comments
 (0)