3. Type Annotations Decorators
By Bernd Klein. Last modified: 13 Jul 2023.
This chapter of our Python course is about decorators but only about how to annotate decorators with type annotations or type hints. If you want to learn all about decorators, we highly recommend our tutorials on Python decorators:
You will learn in this chapter how to annotate decorator functions, allowing you to enhance code readability and maintainability. We provide explanations of the syntax and demonstrate the benefits of using type annotations in your decorators.
Our first example will be a decorator for calling how often a function has been called.
You have to know a few things about the Jupyter-Notebooks cells (ipython shell) to understand how we save programs and start mypy
: With the shell magic %%writefile example1.py
we can write the content of a cell into a file with the name example1.py
.
In IPython syntax, the exclamation mark (!) allows users to run shell commands (from your operating system) from inside a Jupyter Notebook code cell. Simply start a line of code with ! and it will run the command in the shell. We use this to call mypy
on the Python file.
%%writefile example.py
from math import sin, cos
from typing import Callable
def call_counter(func: Callable) -> Callable:
def wrapper(*args, **kwargs):
wrapper.counter += 1
return func(*args, **kwargs)
setattr(wrapper, 'counter', 0)
# not possible:
setattr(wrapper, 'counter', 0)
return wrapper
sin = call_counter(sin)
cos = call_counter(cos)
@call_counter
def add(a: int, b: int) -> int:
return a + b
result = add(5, 3)
print(result)
print(sin(3.5))
print(sin(36.5))
print(getattr(sin, 'counter'))
OUTPUT:
Overwriting example.py
We can see that this Python code above works, if we let it run with Python:
!python example.py
OUTPUT:
8 -0.35078322768961984 -0.9317168878547055 2
We can also see that it works with mypy
as well:
!mypy example.py
OUTPUT:
Success: no issues found in 1 source file
The Future: PEP-612 with ParamSpec and Concatenate
%%writefile example.py
from typing import Callable, Any, Dict
def memoize(f: Callable) -> Callable:
memo: Dict[Any, Any] = {}
def helper(x: Any) -> Any:
if x not in memo:
memo[x] = f(x)
return memo[x]
return helper
def fib(n: int) -> int:
if n == 0:
return 0
elif n == 1:
return 1
else:
return fib(n-1) + fib(n-2)
fib = memoize(fib)
fib(10)
OUTPUT:
Overwriting example.py
!mypy example.py
OUTPUT:
Success: no issues found in 1 source file
Live Python training
Enjoying this page? We offer live Python training courses covering the content of this site.