Decorators in python
Understanding Decorators in Python
Decorators are one of the most confusing Python topics initially because you see syntax like:
@classmethod
or
@staticmethod
and it feels like magic.
The good news is that decorators are actually just functions that modify other functions.
Step 1: Functions Are Objects in Python
In Python, functions are objects.
You can store them in variables.
def greet():
print("Hello")
say_hello = greet
say_hello()
Output
Hello
Here:
say_hello = greet
stores the function inside another variable.
Step 2: Functions Can Receive Functions
def greet():
print("Hello")
def execute(func):
func()
execute(greet)
Output
Hello
Notice:
execute(greet)
passes a function as an argument.
Step 3: Functions Can Return Functions
def outer():
def inner():
print("Hello")
return inner
func = outer()
func()
Output
Hello
The outer function returns another function.
Step 4: Build a Simple Decorator
Suppose we want to add extra behavior before and after a function.
Original function:
def greet():
print("Hello")
Desired output:
Before
Hello
After
Decorator:
def decorator(func):
def wrapper():
print("Before")
func()
print("After")
return wrapper
Use it:
def greet():
print("Hello")
greet = decorator(greet)
greet()
Output
Before
Hello
After
What Happened?
Originally:
greet()
called:
Hello
After:
greet = decorator(greet)
the variable greet now points to:
wrapper()
instead of the original function.
So calling:
greet()
actually calls:
wrapper()
which then calls the original function.
Step 5: Decorator Syntax (@)
Python provides shorthand syntax.
Instead of:
def greet():
print("Hello")
greet = decorator(greet)
you can write:
@decorator
def greet():
print("Hello")
Python automatically converts it into:
def greet():
print("Hello")
greet = decorator(greet)
These two are identical.
Why Are Decorators Useful?
They let you add behavior without changing the original function.
Example uses:
- Logging
- Authentication
- Timing
- Validation
- Caching
- Permissions
Real Example: Timing a Function
import time
def timer(func):
def wrapper():
start = time.time()
func()
end = time.time()
print("Time:", end - start)
return wrapper
Use:
@timer
def work():
for i in range(1000000):
pass
work()
Output
Time: 0.02
(The exact number varies.)
Now Let's Understand @classmethod
When Python sees:
class Student:
@classmethod
def get_school(cls):
return cls.school
Python converts it roughly to:
class Student:
def get_school(cls):
return cls.school
get_school = classmethod(get_school)
Notice:
classmethod(get_school)
is a decorator function.
It changes how the method behaves.
Instead of receiving:
self
it receives:
cls
Another Example
Without decorator:
class Test:
def show(self):
print("Hello")
Object needed:
t = Test()
t.show()
With decorator:
class Test:
@classmethod
def show(cls):
print("Hello")
Call directly from class:
Test.show()
No object required.
The decorator changes the behavior.
Common Built-in Decorators
@classmethod
Works with the class.
@classmethod
def method(cls):
pass
@staticmethod
Works without object or class.
@staticmethod
def add(a, b):
return a + b
@property
Makes a method behave like an attribute.
class Student:
@property
def name(self):
return "John"
Usage:
s = Student()
print(s.name)
Notice:
s.name
not:
s.name()
The decorator changes the behavior.
The Simplest Definition
A decorator is a function that takes another function and returns a modified version of that function.
@decorator
def my_function():
pass
is equivalent to:
def my_function():
pass
my_function = decorator(my_function)
Rule to Remember
Decorator
↓
Receives a function
↓
Modifies behavior
↓
Returns a new function
Think of a decorator as a wrapper around a function. It can add extra behavior before the function runs, after it runs, or even change how it is called.