Python Decorators

Python Decorators

A decorator in Python is one of the most powerful tools that enhance the function behavior, method, or class without modifying its actual structure or code. Moreover, decorators are applied before the function definition to alter or extend its behavior. This blog will explain how decorators are effectively used in Python Functions.

Before moving to decorators, we must have a clear understanding of the functions in Python.

Functions in Python are blocks of reusable code that are executed multiple times whenever they are called. Functions can break the code into one or more manageable pieces for better understanding and readability.

def fun1(x,y):
   print(f"the sum of x and y is {x+y}")

fun1(10,20)

Table of Contents

Assigning function to Variable

Functions are first-class objects, meaning you can assign a function to a variable, pass it as an argument, and return from another function

When the function is assigned to a variable, you can call the function through that variable, just like the original function name

def hello(name):
   return f"hi my name is {name}"

greet= hello
print(greet("honey"))
Python: From Basics to Industry Excellence
Hands-On Training for High-Demand Skills. Build, Solve, and Thrive in the Tech World!
quiz-icon

Nested function

A nested function is a function that is defined inside another function, and the inner function can access the variables and methods present in the outer function. This approach helps in organizing the code in a more structured and encapsulated way

def outer_fun(x): z = 10 def inner_fun(y): return x+y+z return inner_fun add_num = outer_fun(10) print(add_num(4))

Passing Functions as Argument to Other Functions

Functions are first-class objects, meaning you can pass a function to another function as an argument This allows for creating higher-order functions, making the code reusable and flexible.

def hi(name):
  return f"hi, {name}!"

def greetings(func , name):
   return func(name)

greet = greetings(hi, "priya")
print(greet)

Return a Function as a Value

As we have already discussed, functions are first-class objects, meaning you can return a function from another defined function. This allows you to create a dynamic function that changes the behavior according to parameters or context

def outer_fun(a):
  def inner_fun(b):
     return a+b

  return inner_fun


add_seven = outer_fun(7)
outcome = add_seven(10)
print(outcome)

Decorators

A decorator is used to modify the behavior or enhance capabilities without modifying the existing code or structure. They can be thought of as wrappers that enhance the functionality of a function or method. This allows for achieving code reusability and modularity.

A decorator takes an input function, wraps it with additional functionality, and returns the enhanced version of that function.

In Python, anything that can be called like a function with parentheses () is something known as a callable. this includes methods, functions, and even objects that implement the __call__() method. Since decorators are themselves functions, they are callable and can be used to modify other callables.

def add_new(func):
  def wrapper():
    print("added extra things")
    func()
  return wrapper
def normal_func():
  print("this is normal")

# apply decorator
decorator_func = add_new(normal_func)
# calling the decorator function
decorator_func()

add_new(func) is a decorator that takes a function (normal_func) and adds extra functionality (added extra things) before calling the original function. When the decorator_func() is called, first it prints (added extra things) and then calls the normal_func() which prints “this is normal.”

@symbol with decorator

The @symbol is used to perform decorator with function. It is a short way of writing the decorator that makes the code cleaner and easier to understand. Essentially, it directly applies the decorator to the function it’s decorating without needing to call the decorator explicitly.

def normal_decorator(func):
  def wrapper():
    print('before the function execution')
    func()
    print("after the function execution")

  return wrapper


@normal_decorator
def say_hii():
   print("hey!")

# Calling the decorated function

say_hii()
Free Python Course – Your Gateway to Industry-Level Expertise!
Build real-world projects and kickstart your tech career today
quiz-icon

Passing Argument to the Decorator

A Python decorator with arguments accepts additional arguments alongside its function decorator. This is beneficial when you want the decorator to modify its behavior based on external inputs.

def repetition(n):
  def decorator(func):
    def wrapper(*args, **kwargs):
      for i in range(n):
        func(*args, **kwargs)
    return wrapper
  return decorator


@repetition(4)
def hi(name):
  print(f"hy, {name}")

# calling the decorated func
hi("sumit")

Common built-in decorators in Python

Here are some built-in decorators in Python :

@staticmethod

This @staticmethod does not require or depend on the instance or class to be called for execution. This means @staticmethod can be called without creating any object or instance of the class, i.e., it can be called directly using the class name.

class Mathcalculations:
   @staticmethod
   def addition(a,b):
    return a+b

   @staticmethod
   def subtraction(a,b):
     return a-b

# calling static method without object creation
print(Mathcalculations.addition(10,2))
print(Mathcalculations.subtraction(11,20))

# We can also call the static method through  an instance
math_instance = Mathcalculations()
print(math_instance.addition(10,2))

@classmethod

@classmethod is a method that is bound to the class itself rather than the instance. In regular methods, we take self as a first parameter, but @classmethod takes cls as the first parameter, which refers to the class itself. This allows the method to modify the class-level data and its properties, and it can be called from the class or an instance of the class.

class People:
  name = "undefined"
   
  @classmethod
  def sets_name(cls, new_name):
    cls.name = new_name

  @classmethod
  def display1(cls):
    print(f"Name: {cls.name}")

#calling class method using class name
People.sets_name("Niyomi")
People.display1()


# calling class method using instance
People_instance =People()
People_instance.display1()

@property

This @property decorator defines a method as a property, meaning it allows you to define a method that behaves as an attribute. You can access it as if it were a simple variable without needing to call it explicitly as a method(without parentheses).

class Circle:
  def __init__(self, rad):
    self._rad = rad

  @property
  def rad(self):
    return self._rad

  @property
  def area(self):
    return 3.14 *self._rad**2


circle = Circle(10)
print(f"radius: {circle.rad}")
print(f"area: {circle.area}")

Chaining decorators

Chaining decorators refers to applying multiple decorators to one function or method, one after another. Every decorator wraps the function and enhances or modifies its behavior.

# first decorator
def decorator_first(func):
  def wrapper():
    print("first decorator applied ")
    func()

  return wrapper

#second decorator
def decorator_second(func):
  def wrapper():
    print("2nd decorator applied")
    func()
  return wrapper

# Applying both the decorators
@decorator_first
@decorator_second
def hey():
  print("hello everyone")


hey()

Watch the video below to learn more about decorators

Video Thumbnail

Get 100% Hike!

Master Most in Demand Skills Now!

Conclusion

Python decorators are one of the prominent aspects of functions that help you add functionality to your function for the enhancement of the existing version without modifying the actual code. They tend to make your code modular, avoid duplication, and improve readability. If you want to learn more about Python, then do check out our latest Python course.

About the Author

Principal Data Scientist

Meet Akash, a Principal Data Scientist with expertise in advanced analytics, machine learning, and AI-driven solutions. With a master’s degree from IIT Kanpur, Aakash combines technical knowledge with industry insights to deliver impactful, scalable models for complex business challenges.

EPGC Data Science Artificial Intelligence