Deep dive into Python decorators with advanced class method examples

Understanding Python Decorators Python decorators are a powerful, advanced feature that allows for the modification and enhancement of functions or methods. They provide a way to wrap a function or method in order to extend

Written by: Leo Nguyen

Published on: October 21, 2025

Understanding Python Decorators

Python decorators are a powerful, advanced feature that allows for the modification and enhancement of functions or methods. They provide a way to wrap a function or method in order to extend its behavior without permanently modifying it.

What are Decorators?

At their core, decorators are functions that take another function as an argument and extend its functionality. The primary purpose of decorators in Python is to provide a flexible way to alter the behavior of a function or method at runtime.

Basics of Function Decorators

Before discussing class method decorators, let’s look at a basic function decorator.

def simple_decorator(func):
    def wrapper():
        print("Before function call")
        func()
        print("After function call")
    return wrapper

@simple_decorator
def say_hello():
    print("Hello!")

say_hello()

In this example, the simple_decorator wraps around the say_hello function. When you call say_hello(), the output is:

Before function call
Hello!
After function call

This illustrates how decorators can enhance the behavior of functions in a clean and readable manner.

Class Method Decorators

Class method decorators are used to extend or modify class methods (including static methods and instance methods). The primary use cases include enforcement of access controls, logging, validation of inputs, and more.

Defining Class Method Decorators

Let’s define a simple class method decorator that logs method calls.

def log_method_call(method):
    def wrapper(self, *args, **kwargs):
        print(f"Calling {method.__name__} with arguments {args} and keyword arguments {kwargs}")
        result = method(self, *args, **kwargs)
        print(f"{method.__name__} returned {result}")
        return result
    return wrapper

This decorator can be applied to class methods to log their parameters and return values.

Example of Class Method Using Decorators

Now, let’s see how we can implement our log_method_call decorator in a class.

class Calculator:

    @log_method_call
    def add(self, a, b):
        return a + b

    @log_method_call
    def subtract(self, a, b):
        return a - b

calc = Calculator()
result_add = calc.add(5, 3)
result_subtract = calc.subtract(10, 4)

When invoking the add and subtract methods, the console output will look something like this:

Calling add with arguments (5, 3) and keyword arguments {}
add returned 8
Calling subtract with arguments (10, 4) and keyword arguments {}
subtract returned 6

This example shows that decorators can be applied to class methods, providing additional behavior cleanly and understandably.

Using Classmethod and Staticmethod Decorators

Python provides built-in decorators such as @classmethod and @staticmethod that modify the way methods behave within classes. Let’s define a class that utilizes both:

class MathUtils:

    @staticmethod
    def multiply(a, b):
        return a * b

    @classmethod
    def from_array(cls, array):
        return cls(*array)

# Using static method
product = MathUtils.multiply(3, 4)  # returns 12

# Using class method
math_instance = MathUtils.from_array([10, 20])  # Creates instance from array

Advanced Decorators: Access Control Example

Let’s design a decorator for access control. This can be especially useful in situations where certain users need specific permissions.

def requires_permission(permission):
    def decorator(method):
        def wrapper(self, *args, **kwargs):
            if permission not in self.user_permissions:
                raise PermissionError(f"You do not have the '{permission}' permission.")
            return method(self, *args, **kwargs)
        return wrapper
    return decorator

class RestrictedResource:
    def __init__(self, user_permissions):
        self.user_permissions = user_permissions

    @requires_permission('access_resource')
    def access_resource(self):
        return "Resource accessed!"

user = RestrictedResource(user_permissions=['access_resource'])

# Successful access
print(user.access_resource())

# Unsuccessful access
restricted_user = RestrictedResource(user_permissions=[])
# This would raise PermissionError.

Memoization with Decorators

One of the advanced use cases for decorators is memoization, which can cache method results for performance-efficient calculations.

def memoize(func):
    cache = {}

    def wrapper(*args):
        if args in cache:
            return cache[args]
        result = func(*args)
        cache[args] = result
        return result
    return wrapper

class FibonacciCalculator:

    @memoize
    def fibonacci(self, n):
        if n < 2:
            return n
        return self.fibonacci(n - 1) + self.fibonacci(n - 2)

fib_calc = FibonacciCalculator()

Decorators with Parameters

You can also create decorators that accept parameters for enhanced flexibility. Here’s how this works:

def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                func(*args, **kwargs)
        return wrapper
    return decorator

class Greeter:

    @repeat(3)
    def greet(self, name):
        print(f"Hello, {name}!")

greeter = Greeter()
greeter.greet('Alice')

The above example will print “Hello, Alice!” three times, showcasing how decorators can be parameterized.

Combining Multiple Decorators

Sometimes, you may want to combine multiple decorators. The order of application is significant:

def decorator_one(func):
    def wrapper(*args, **kwargs):
        print("Decorator One")
        return func(*args, **kwargs)
    return wrapper

def decorator_two(func):
    def wrapper(*args, **kwargs):
        print("Decorator Two")
        return func(*args, **kwargs)
    return wrapper

class Demo:

    @decorator_one
    @decorator_two
    def display(self):
        print("Display Method Called!")

demo = Demo()
demo.display()

This results in:

Decorator One
Decorator Two
Display Method Called!

Conclusion

Python decorators offer extensive opportunities for extending and modifying the behavior of functions and methods. Their applications range from logging and access control to caching and performance optimizations. Understanding and utilizing decorators effectively within class methods can lead to cleaner, more maintainable, and highly reusable code structures. Whether you’re implementing simple logging or complex access control mechanisms, decorators in Python enhance your code’s legibility and reusability dramatically.

Leave a Comment

Previous

Best practices for configuring your Python development environment on Windows 11

Next

Essential tools for setting up a productive Python workspace on Windows 11