Decorators in Python

Overview

This lesson covers decorators in Python, a powerful feature that allows you to modify the behavior of functions or methods. Understanding decorators can greatly enhance your ability to write readable, efficient, and elegant Python code.

Introduction

A decorator in Python is a function that takes another function as an argument, adds some kind of functionality or modification to the input function, and returns a modified function. Decorators provide a flexible way to extend the behavior of functions without permanently modifying them.

Basic Concept

  • Decorator Syntax: In Python, decorators are applied to functions using the @ symbol followed by the decorator function name before the function definition.
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!")

How Decorators Work

  • When you decorate a function with @my_decorator, you’re essentially saying, “Apply my_decorator to say_hello.”
  • The say_hello function is passed to my_decorator as an argument (func), and the wrapper function adds behavior before and after calling say_hello within it.

Using Decorators

  • With Arguments: If the original function takes arguments, the wrapper function must also take those arguments (or use *args and **kwargs to accept an arbitrary number of arguments).
def decorator_with_args(func):
    def wrapper(*args, **kwargs):
        print("Something before the original function is called.")
        result = func(*args, **kwargs)
        print("Something after the original function is called.")
        return result
    return wrapper

Built-in Decorators

  • Python includes several built-in decorators, like @staticmethod, @classmethod, and @property, which are commonly used in object-oriented programming.

Chaining Decorators

  • Decorators can be stacked, allowing you to apply multiple modifications to a function.
@decorator_one
@decorator_two
def my_function():
    pass

Practical Uses

  • Logging: Use decorators to log when a function is called.
  • Timing: Measure how long a function takes to execute.
  • Authorization: Check if a user has permission to execute a function.
  • Caching/Memoization: Store the results of expensive function calls and return the cached result when the same inputs occur again.

Conclusion

Decorators are a significant part of Python’s expressive power, allowing for concise, readable, and efficient code. By mastering decorators, you can write code that is more modular, reusable, and easy to change or extend.

Additional Resources