Annotations#
Python has an option to annotate types, which is useful during relatively serious development.
Check resources:
Python type checking article on real python.
typing package description - contains typical patterns for annotation using.
PEP 484 that introduce type hints.
PEP 526 that introduce variable annotations.
import sys
sys.path.append("/tmp")
Usecases#
In general, you can define types of parameters and return values for the function and specify the type for some variable/attribute. This doesn’t affect the behavior of the interpreter in any way, but different code analisys tools make use of it.
The following cell creates python file that defines function that expect to take float
and int
and return bool
. The function is wrapped with typeguard.typechecked
decorator, which throws raise an error every time it is called with wrong types.
%%writefile /tmp/typed_fun.py
from typeguard import typechecked
@typechecked
def some_function(arg1: float, arg2: int) -> bool:
return arg1 > arg2
Overwriting /tmp/typed_fun.py
The following code shows the exception you get when you try to pass parameters of the wrong type to the function.
from typed_fun import some_function
try: some_function(5.5, 3.3)
except Exception as e: print(e)
argument "arg2" (float) is not an instance of int
The next cell generates a file that contains a variable that shoudl be of the datatype float
datatype, but assigns str
to the variable.
%%writefile /tmp/typed_var.py
pi: float = "test"
Overwriting /tmp/typed_var.py
mypy
static analisator throws corresponding error to that file.
!python3 -m mypy /tmp/typed_var.py
/tmp/typed_var.py:1: error: Incompatible types in assignment (expression has type "str", variable has type "float") [assignment]
Found 1 error in 1 file (checked 1 source file)
Annotation cases#
This section provided an overview of the various syntax and typing
attributes that can be used to define types.
Category |
Syntax |
Description |
Example |
---|---|---|---|
Basic types |
|
Built-in types |
|
Union |
|
One of several types |
|
Optional |
|
Shorthand for |
|
List |
|
A list of items |
|
Tuple |
|
A fixed-size tuple |
|
Dict |
|
Dictionary with keys and values |
|
Set |
|
A set of items |
|
Callable |
|
A function signature |
|
Literal |
|
Restrict to specific literal values |
|
Any |
|
Skip type checking |
|
None |
|
Variable takes |
|
NoReturn |
|
Function never returns |
|
Annotated |
|
Attach metadata to a type |
|
NewType |
|
Create a distinct type based on an existing one |
|
TypeVar |
|
Generic type variable |
|
Generic |
|
Base class for generic classes |
|
Self |
|
Return type of method returning its own class |
|
ClassVar |
|
Type of class-level variables |
|
Final |
|
Marks values as constants |
|
TypedDict |
|
Dict with specific key types |
|
Protocol |
|
Structural subtyping (duck typing) |
|
Union with ellipsis |
|
Homogeneous tuple of any length |
|
Predefinition |
|
If the type isn’t defined yet use literal as annotation |
|
Check more accurate description with examples on the conrresponding page.
Type aliases#
Note that you can save your annotations as regular python object - your programmes will be neater.
Below is an example that defines a function to create triangles as a tuple of three two-dimensional points.
from random import random
def get_triangle() -> tuple[
tuple[float, float],
tuple[float, float],
tuple[float, float]
]:
return (
(random(), random()),
(random(), random()),
(random(), random())
)
To make things simplier, you can define an annotation for the point and use it to define an annotation for the triangle.
point = tuple[float, float]
def get_triangle() -> tuple[point, point, point]:
return (
(random(), random()),
(random(), random()),
(random(), random())
)
__annotations__
attribute#
The __annotations__
attribute allows you to retrieve annotated types for a Python object.
For function it returns a dictionary with keys corresponding to the names of the arguments and values corresponding to the types of the arguments. The return type of the function can be accessed using the return
key.
def some_function(arg1: float, arg2: bool) -> int | None:
if arg1 > 10 and arg2:
return 20
some_function.__annotations__
{'arg1': float, 'arg2': bool, 'return': int}
You can simply access it from any Python namespace to get annotations of the waribles in that namespace.
new_variable : float = 10
test_variable : float = 10
__annotations__
{'new_variable': float, 'test_variable': float}