Python Interview Questions

32 Questions
Python

Python

Web DevelopmentFrontendBackendData Science

Question 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 takes say_hello as an argument.
  • The wrapper function inside my_decorator adds behavior before and after the call to func().
  • The @my_decorator syntax is a shorthand for say_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.

Recent job openings