Sign in to your Python Morsels account to save your screencast settings.
Don't have an account yet? Sign up here.
What decorators are included with Python?
Python's functools module includes a cache decorator, which will cache the return values of a specific function.
from functools import cache
from math import isqrt
@cache
def is_prime(n):
"""Determine if a non-negative integer is prime."""
if not isinstance(n, int) or n < 0:
raise ValueError("Input must be a non-negative integer.")
if n < 2:
return False
for i in range(2, isqrt(n) + 1):
if n % i == 0:
return False
return True
Whenever a cache-decorated function is called with the same arguments that it has already been called with, a cached version of the return value will be used:
So if we pass a very large prime number to this is_prime function, it may take a few seconds to run to compute an answer:
>>> is_prime(10657331232548839)
True
But if we pass the same number again, it will return the same return value immediately.
>>> is_prime(10657331232548839)
True
The cache decorator keeps track of the arguments that a function is called with.
For each unique argument signature, the return value is cached, and then reused if the function is called with the same arguments again.
Python's functools module also includes an lru_cache decorator, which works like the cache decorator, except that a maximum cache size can also be supplied:
from functools import lru_cache
from math import isqrt
@lru_cache(maxsize=256)
def is_prime(n):
"""Determine if a non-negative integer is prime."""
if not isinstance(n, int) or n < 0:
raise ValueError("Input must be a non-negative integer.")
if n < 2:
return False
for i in range(2, isqrt(n) + 1):
if n % i == 0:
return False
return True
Note that the lru_cache decorator accepts an argument.
We will see how to make decorators that accept arguments later.
Python also includes class decorators, such as the dataclass decorator from Python's dataclasses module.
Here's a class called Transfer, which has three methods within it:
class Transfer:
def __init__(self, sender, receiver, amount, memo):
self.sender = sender
self.receiver = receiver
self.amount = amount
self.memo = memo
def __repr__(self):
cls = type(self).__name__
return (
f"{cls}(sender={self.sender!r}, receiver={self.receiver!r}, " +
f"amount={self.amount!r}, memo={self.memo!r})"
)
def __eq__(self, other):
if not isinstance(other, Transfer):
return NotImplemented
mine = (self.sender, self.receiver, self.amount, self.memo)
theirs = (other.sender, other.receiver, other.amount, other.memo)
return mine == theirs
Instead of that 3-method Transfer class, we can use the dataclass decorator from Python's dataclasses module:
from dataclasses import dataclass
@dataclass
class Transfer:
sender: str
receiver: str
amount: float
memo: str
Note that the dataclass decorator is applied to classes, not functions.
This type of decorator is often called a class decorator.
property, classmethod, contextmanager, and moreThese are not the only three decorators included with Python.
Python also includes a property decorator, a classmethod decorator, a contextmanager decorator and other decorators.
There are also decorators included in third-party libraries. And you can even make your own decorators, which we'll be doing later.
Need to fill-in gaps in your Python skills?
Sign up for my Python newsletter where I share one of my favorite Python tips every week.
Sign in to your Python Morsels account to track your progress.
Don't have an account yet? Sign up here.