Python26 min read
Python Decorators
Understand decorators deeply: why they exist, how wrapper functions work, decorators with args, and real use cases like logging and access control.
Michael Brown
August 18, 2025
7.5k155
Decorators are a Python feature that lets you wrap a function to add extra behavior without changing the function’s core logic.
Think of it like adding a cover on a phone:
- the phone stays the same
- the cover adds protection and extra features
In code:
- your function stays the same
- the decorator adds timing, logging, validation, permissions, and more
## Step 1: functions can be passed around
```python
def greet():
return "hello"
def call_function(func):
return func()
print(call_function(greet))
```
Expected output:
```
hello
```
## Step 2: a decorator is a function that returns a new function
```python
def uppercase_decorator(func):
def wrapper():
result = func()
return result.upper()
return wrapper
@uppercase_decorator
def greet():
return "hello from boston"
print(greet())
```
Expected output:
```
HELLO FROM BOSTON
```
### What changed?
- You still call `greet()`
- But now it runs through `wrapper()` first
## Decorators with arguments (repeat example)
```python
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def say_hi(name):
print(f"Hi {name}!")
say_hi("Tom")
```
Expected output:
```
Hi Tom!
Hi Tom!
Hi Tom!
```
## Real-world example: timing a function
```python
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"Time: {end - start:.4f}s")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
print("Done!")
slow_function()
```
Expected output example:
```
Done!
Time: 1.00xxs
```
## Graph: decorator flow
```mermaid
flowchart LR
A[Call function] --> B[Decorator wrapper]
B --> C[Original function]
C --> D[Return result]
D --> E[Decorator adds behavior]
```
## Common decorator mistakes
- forgetting `*args, **kwargs` (breaks functions that take parameters)
- not returning the function result when needed
- writing decorators that hide errors
In the next lesson, you will learn generators, which help you process large data efficiently without loading everything into memory.
#Python#Intermediate#Decorators