blob: cc9fef3f35e89f640279e82909287ba1acd82351 [file]
.. _cheat-sheet-py3:
Mypy syntax cheat sheet (Python 3)
==================================
This document is a quick cheat sheet showing how the `PEP 484 <https://www.python.org/dev/peps/pep-0484/>`_ type
language represents various common types in Python 3. Unless otherwise noted, the syntax is valid on all versions of Python 3.
.. note::
Technically many of the type annotations shown below are redundant,
because mypy can derive them from the type of the expression. So
many of the examples have a dual purpose: show how to write the
annotation, and show the inferred types.
Built-in types
**************
.. code-block:: python
from typing import List, Set, Dict, Tuple, Text, Optional, AnyStr
# For simple built-in types, just use the name of the type.
x = 1 # type: int
x = 1.0 # type: float
x = True # type: bool
x = "test" # type: str
x = u"test" # type: str
x = b"test" # type: bytes
# For collections, the name of the type is capitalized, and the
# name of the type inside the collection is in brackets.
x = [1] # type: List[int]
x = {6, 7} # type: Set[int]
# For mappings, we need the types of both keys and values.
x = {'field': 2.0} # type: Dict[str, float]
# For tuples, we specify the types of all the elements.
x = (3, "yes", 7.5) # type: Tuple[int, str, float]
# For textual data, use Text.
# This is `unicode` in Python 2 and `str` in Python 3.
x = ["string", u"unicode"] # type: List[Text]
# Use Optional for values that could be None.
input_str = f() # type: Optional[str]
if input_str is not None:
print(input_str)
Functions
*********
Python 3 introduces an annotation syntax for function declarations in `PEP 3107 <https://www.python.org/dev/peps/pep-3107/>`_.
.. code-block:: python
from typing import Callable, Iterable, Union, Optional, List
# This is how you annotate a function definition.
def stringify(num: int) -> str:
return str(num)
# And here's how you specify multiple arguments.
def plus(num1: int, num2: int) -> int:
return num1 + num2
# Add type annotations for kwargs as though they were positional args.
def f(num1: int, my_float: float = 3.5) -> float:
return num1 + my_float
# An argument can be declared positional-only by giving it a name
# starting with two underscores:
def quux(__x: int) -> None:
pass
quux(3) # Fine
quux(__x=3) # Error
# This is how you annotate a function value.
x = f # type: Callable[[int, float], float]
# A generator function that yields ints is secretly just a function that
# returns an iterable (see below) of ints, so that's how we annotate it.
def f(n: int) -> Iterable[int]:
i = 0
while i < n:
yield i
i += 1
# For a function with many arguments, you can of course split it over multiple lines
def send_email(address: Union[str, List[str]],
sender: str,
cc: Optional[List[str]],
bcc: Optional[List[str]],
subject='',
body: List[str] = None
) -> bool:
...
When you're puzzled or when things are complicated
**************************************************
.. code-block:: python
from typing import Union, Any, List, cast
# To find out what type mypy infers for an expression anywhere in
# your program, wrap it in reveal_type. Mypy will print an error
# message with the type; remove it again before running the code.
reveal_type(1) # -> error: Revealed type is 'builtins.int'
# Use Union when something could be one of a few types.
x = [3, 5, "test", "fun"] # type: List[Union[int, str]]
# Use Any if you don't know the type of something or it's too
# dynamic to write a type for.
x = mystery_function() # type: Any
# Use `ignore` to suppress type-checking on a given line, when your
# code confuses mypy or runs into an outright bug in mypy.
# Good practice is to comment every `ignore` with a bug link
# (in mypy, typeshed, or your own code) or an explanation of the issue.
x = confusing_function() # type: ignore # https://github.com/python/mypy/issues/1167
# cast is a helper function for mypy that allows for guidance of how to convert types.
# it does not cast at runtime
a = [4]
b = cast(List[int], a) # passes fine
c = cast(List[str], a) # passes fine (no runtime check)
reveal_type(c) # -> error: Revealed type is 'builtins.list[builtins.str]'
print(c) # -> [4] the object is not cast
# TODO: explain "Need type annotation for variable" when
# initializing with None or an empty container
Standard duck types
*******************
In typical Python code, many functions that can take a list or a dict
as an argument only need their argument to be somehow "list-like" or
"dict-like". A specific meaning of "list-like" or "dict-like" (or
something-else-like) is called a "duck type", and several duck types
that are common in idiomatic Python are standardized.
.. code-block:: python
from typing import Mapping, MutableMapping, Sequence, Iterable, List, Set
# Use Iterable for generic iterables (anything usable in `for`),
# and Sequence where a sequence (supporting `len` and `__getitem__`) is required.
def f(iterable_of_ints: Iterable[int]) -> List[str]:
return [str(x) for x in iterable_of_ints]
f(range(1, 3))
# Mapping describes a dict-like object (with `__getitem__`) that we won't mutate,
# and MutableMapping one (with `__setitem__`) that we might.
def f(my_dict: Mapping[int, str])-> List[int]:
return list(my_dict.keys())
f({3: 'yes', 4: 'no'})
def f(my_mapping: MutableMapping[int, str]) -> Set[str]:
my_mapping[5] = 'maybe'
return set(my_mapping.values())
f({3: 'yes', 4: 'no'})
Classes
*******
.. code-block:: python
class MyClass:
# The __init__ method doesn't return anything, so it gets return
# type None just like any other method that doesn't return anything.
def __init__(self) -> None:
...
# For instance methods, omit `self`.
def my_class_method(self, num: int, str1: str) -> str:
return num * str1
# User-defined classes are written with just their own names.
x = MyClass() # type: MyClass
Other stuff
***********
.. code-block:: python
import sys
import re
# typing.Match describes regex matches from the re module.
from typing import Match, AnyStr, IO
x = re.match(r'[0-9]+', "15") # type: Match[str]
# You can use AnyStr to indicate that any string type will work
# but not to mix types
def full_name(first: AnyStr, last: AnyStr) -> AnyStr:
return first+last
full_name('Jon','Doe') # same str ok
full_name(b'Bill', b'Bit') # same binary ok
full_name(b'Terry', 'Trouble') # different str types, fails
# Use IO[] for functions that should accept or return any
# object that comes from an open() call. The IO[] does not
# distinguish between reading, writing or other modes.
def get_sys_IO(mode='w') -> IO[str]:
if mode == 'w':
return sys.stdout
elif mode == 'r':
return sys.stdin
else:
return sys.stdout
# forward references are useful if you want to referemce a class before it is designed
def f(foo: A) -> int: # this will fail
...
class A:
...
# however, using the string 'A', it will pass as long as there is a class of that name later on
def f(foo: 'A') -> int:
...
# TODO: add TypeVar and a simple generic function
Variable Annotation in Python 3.6 with PEP 526
**********************************************
Python 3.6 brings new syntax for annotating variables with `PEP 526 <https://www.python.org/dev/peps/pep-0526/>`_.
Mypy brings limited support for PEP 526 annotations.
.. code-block:: python
# annotation is similar to arguments to functions
name: str = "Eric Idle"
# class instances can be annotated as follows
mc : MyClass = MyClass()
# tuple packing can be done as follows
tu: Tuple[str, ...] = ('a', 'b', 'c')
# annotations are not checked at runtime
year: int = '1972' # error in type checking, but works at runtime
# these are all equivalent
hour = 24 # type: int
hour: int; hour = 24
hour: int = 24
# you do not (!) need to initialize a variable to annotate it
a: int # ok for type checking and runtime
# which is useful in conditional branches
child: bool
if age < 18:
child = True
else:
child = False
# annotations for classes are for instance variables (those created in __init__ or __new__)
class Battery:
charge_percent: int = 100 # this is an instance variable with a default value
capacity: int # an instance variable without a default
# you can use the ClassVar annotation to make the variable a class variable instead of an instance variable.
class Car:
seats: ClassVar[int] = 4
passengers: ClassVar[List[str]]
# You can also declare the type of an attribute in __init__
class Box:
def __init__(self) -> None:
self.items: List[str] = []
Please see :ref:`python-36` for more on mypy's compatability with Python 3.6's new features.