Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to cheat sheet #14972

Merged
merged 3 commits into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 51 additions & 38 deletions docs/source/cheat_sheet_py3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ See :ref:`type-inference-and-annotations` for more details.
# You don't need to initialize a variable to annotate it
a: int # Ok (no value at runtime until assigned)

# Doing so is useful in conditional branches
# Doing so can be useful in conditional branches
child: bool
if age < 18:
child = True
Expand All @@ -34,7 +34,7 @@ Useful built-in types

.. code-block:: python

# For most types, just use the name of the type.
# For most types, just use the name of the type in the annotation
# Note that mypy can usually infer the type of a variable from its value,
# so technically these annotations are redundant
x: int = 1
Expand Down Expand Up @@ -75,10 +75,11 @@ Useful built-in types
# Use Optional[X] for a value that could be None
# Optional[X] is the same as X | None or Union[X, None]
x: Optional[str] = "something" if some_condition() else None
# Mypy understands a value can't be None in an if-statement
if x is not None:
# Mypy understands x won't be None here because of the if-statement
print(x.upper())
# If a value can never be None due to some invariants, use an assert
# If you know a value can never be None due to some logic that mypy doesn't
# understand, use an assert
assert x is not None
print(x.upper())

Expand Down Expand Up @@ -259,6 +260,8 @@ When you're puzzled or when things are complicated
In some cases type annotations can cause issues at runtime, see
:ref:`runtime_troubles` for dealing with this.

See :ref:`silencing-type-errors` for details on how to silence errors.

Standard "duck types"
*********************

Expand Down Expand Up @@ -294,37 +297,11 @@ that are common in idiomatic Python are standardized.

f({3: 'yes', 4: 'no'})


You can even make your own duck types using :ref:`protocol-types`.

Coroutines and asyncio
**********************

See :ref:`async-and-await` for the full detail on typing coroutines and asynchronous code.

.. code-block:: python

import asyncio

# A coroutine is typed like a normal function
async def countdown35(tag: str, count: int) -> str:
while count > 0:
print(f'T-minus {count} ({tag})')
await asyncio.sleep(0.1)
count -= 1
return "Blastoff!"


Miscellaneous
*************

.. code-block:: python

import sys
from typing import IO

# Use IO[] for functions that should accept or return any
# object that comes from an open() call (IO[] does not
# Use IO[str] or IO[bytes] for functions that should accept or return
# objects that come from an open() call (note that IO[] does not
hauntsaninja marked this conversation as resolved.
Show resolved Hide resolved
# distinguish between reading, writing or other modes)
def get_sys_IO(mode: str = 'w') -> IO[str]:
if mode == 'w':
Expand All @@ -334,19 +311,38 @@ Miscellaneous
else:
return sys.stdout

# Forward references are useful if you want to reference a class before
# it is defined

You can even make your own duck types using :ref:`protocol-types`.

Forward references
******************

.. code-block:: python

# You may want to reference a class before it is defined.
# This is known as a "forward reference".
def f(foo: A) -> int: # This will fail at runtime with 'A' is not defined
...

class A:
# However, if you add the following magic import:
hauntsaninja marked this conversation as resolved.
Show resolved Hide resolved
from __future__ import annotations
# It will work at runtime and type checking will succeed as long as there
# is a class of that name later on in the file
def f(foo: A) -> int: # Ok
...

# If you use the string literal 'A', it will pass as long as there is a
# class of that name later on in the file
def f(foo: 'A') -> int: # Ok
# Another option is to just put the type in quotes
def f(foo: 'A') -> int: # Also ok
...

class A:
# This can also come up if you need to reference a class in a type
# annotation inside the definition of that class
@classmethod
def create(cls) -> A:
...

See :ref:`forward-references` for more details.

Decorators
**********
Expand All @@ -365,3 +361,20 @@ Decorator functions can be expressed via generics. See

def decorator_args(url: str) -> Callable[[F], F]:
...

Coroutines and asyncio
**********************

See :ref:`async-and-await` for the full detail on typing coroutines and asynchronous code.

.. code-block:: python

import asyncio

# A coroutine is typed like a normal function
async def countdown35(tag: str, count: int) -> str:
while count > 0:
print(f'T-minus {count} ({tag})')
await asyncio.sleep(0.1)
count -= 1
return "Blastoff!"
2 changes: 2 additions & 0 deletions docs/source/runtime_troubles.rst
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ Since code inside ``if TYPE_CHECKING:`` is not executed at runtime, it provides
a convenient way to tell mypy something without the code being evaluated at
runtime. This is most useful for resolving :ref:`import cycles <import-cycles>`.

.. _forward-references:

Class name forward references
-----------------------------

Expand Down