Syntax
@decorator_name\ndef function():\n ...Examples
Basic Decorator
Writing a simple decorator that adds behavior before and after a function runs.
def announce(func):
def wrapper():
print("Starting function...")
func()
print("Function finished.")
return wrapper
@announce
def say_hello():
print("Hello!")
say_hello()
# Starting function...
# Hello!
# Function finished.Decorator for Functions with Arguments
Using *args and **kwargs so the decorator works with any function signature.
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
print(f"{func.__name__} took {elapsed:.4f}s")
return result
return wrapper
@timer
def slow_add(a, b):
time.sleep(0.1)
return a + b
print(slow_add(3, 4))Preserving Metadata with functools.wraps
Using functools.wraps so the decorated function keeps its original name and docstring.
import functools
def log_call(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_call
def greet(name):
"""Greet someone by name."""
return f"Hello, {name}!"
print(greet("Fola"))
print(greet.__name__) # greet (not "wrapper")Built-in Decorators
Python's standard library includes several ready-made decorators, like functools.lru_cache for memoization.
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(30)) # computed quickly thanks to cachingBest practices
- Always use functools.wraps inside your decorator's wrapper function, so the decorated function keeps its original name, docstring, and metadata
- Accept *args and **kwargs in the wrapper so your decorator works with functions of any signature
- Use built-in decorators like @staticmethod, @classmethod, @property, and @functools.lru_cache before writing your own for common needs
- Keep decorators focused on one concern (logging, timing, caching) rather than bundling multiple responsibilities into one
At a glance
- Purpose
- Scripting and general-purpose applications
- File extension
- .py
- Runs in
- Python interpreter
- Usually used with
- Python standard library and packages
Specifications & further reading
Related Python documentation
The def keyword in Python is used to define functions - reusable blocks of code that perform specific tasks. Functions are fundamental to organizing code, avoiding repetition, and making programs more maintainable. A function can accept inputs (parameters), perform operations, and return outputs. Functions are one of the core building blocks of clean, modular Python code.lambda
A lambda is a small, anonymous, single-expression function, created without the def keyword or a name. Lambdas are restricted to a single expression whose result is automatically returned - they can't contain multiple statements or assignments. They're most useful as short, throwaway functions passed as arguments to other functions like sorted(), map(), and filter().return
The return statement exits a function immediately and optionally sends a value back to the caller. A function can return any type - including multiple values as a tuple - or nothing at all, in which case it implicitly returns None. Once return executes, no further code in the function runs, making it useful for early exits as well as producing a final result.*args and **kwargs
*args and **kwargs let a function accept a variable number of arguments. *args collects any extra positional arguments into a tuple, while **kwargs collects extra keyword arguments into a dictionary. The names 'args' and 'kwargs' are just convention - what matters is the * and ** prefixes. This pattern is common in wrapper functions, decorators, and APIs that need to stay flexible about their inputs.