Python Interview Questions
Python
Web DevelopmentFrontendBackendData ScienceQuestion 15
What is a decorator, and how is it used?
Answer:
A decorator in Python is a function that modifies the behavior of another function or method. Decorators allow you to wrap another function to extend its behavior without permanently modifying it. They are commonly used for logging, access control, memoization, instrumentation, and more.
How Decorators Work
A decorator is a function that takes another function as an argument, adds some kind of functionality, and returns a new function. This is possible because functions in Python are first-class objects, meaning they can be passed around and used as arguments just like any other object (such as integers, strings, lists, etc.).
Basic Decorator Example
Here's a simple example of a decorator:
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
Output:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
In this example:
my_decorator
is a decorator function that takessay_hello
as an argument.- The
wrapper
function insidemy_decorator
adds behavior before and after the call tofunc()
. - The
@my_decorator
syntax is a shorthand forsay_hello = my_decorator(say_hello)
.
Using Decorators with Arguments
If you need to pass arguments to the function being decorated, you need to ensure the wrapper function can accept those arguments. Hereβs how:
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Something is happening before the function is called.")
result = func(*args, **kwargs)
print("Something is happening after the function is called.")
return result
return wrapper
@my_decorator
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Alice")
Output:
Something is happening before the function is called.
Hello, Alice!
Something is happening after the function is called.
Chaining Decorators
You can also apply multiple decorators to a single function. Decorators are applied from the innermost to the outermost.
def decorator1(func):
def wrapper(*args, **kwargs):
print("Decorator 1 before")
result = func(*args, **kwargs)
print("Decorator 1 after")
return result
return wrapper
def decorator2(func):
def wrapper(*args, **kwargs):
print("Decorator 2 before")
result = func(*args, **kwargs)
print("Decorator 2 after")
return result
return wrapper
@decorator1
@decorator2
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Bob")
Output:
Decorator 1 before
Decorator 2 before
Hello, Bob!
Decorator 2 after
Decorator 1 after
Practical Use Cases
1. Logging
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with args {args} and kwargs {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned {result}")
return result
return wrapper
@log_decorator
def add(x, y):
return x + y
add(3, 5)
2. Access Control
def require_authentication(func):
def wrapper(user, *args, **kwargs):
if not user.is_authenticated:
print("User is not authenticated.")
return None
return func(user, *args, **kwargs)
return wrapper
class User:
def __init__(self, authenticated):
self.is_authenticated = authenticated
@require_authentication
def view_profile(user):
print("Profile: User data here.")
user = User(authenticated=True)
view_profile(user) # Profile: User data here.
user = User(authenticated=False)
view_profile(user) # User is not authenticated.
Summary
- A decorator is a function that wraps another function to extend or alter its behavior.
- The
@decorator
syntax is used to apply a decorator to a function. - Decorators can take arguments and can be chained.
- Common use cases include logging, access control, memoization, and more.
Decorators provide a powerful and flexible way to modify the behavior of functions and methods in a clean, readable, and reusable manner.