DEV Community

francesco agati
francesco agati

Posted on

1

Python Decorators: Simplified Explanation

Python decorators are a powerful feature that allows you to modify or extend the behavior of functions or methods without changing their actual code. Let’s explore how decorators work with some simple examples.

Example 1: Logging Decorator

The logging decorator adds functionality to log information about when a function is called and what it returns.

def logger(func):
    def wrapper(*args, **kwargs):
        print(f'Calling {func.__name__} with args={args}, kwargs={kwargs}')
        result = func(*args, **kwargs)
        print(f'{func.__name__} returned {result}')
        return result
    return wrapper
Enter fullscreen mode Exit fullscreen mode

When you decorate a function with @logger, it prints messages before and after calling the function, showing its arguments and return value.

Example 2: Timing Decorator

The timing decorator measures how much time a function takes to execute.

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f'{func.__name__} took {end_time - start_time} seconds to execute')
        return result
    return wrapper
Enter fullscreen mode Exit fullscreen mode

With @timer applied to a function, it calculates and prints the execution time in seconds.

Example 3: Authentication Decorator

The authentication decorator restricts access to a function based on user login status.

logged_in_users = ['alice', 'bob']

def authenticate(func):
    def wrapper(username, *args, **kwargs):
        if username in logged_in_users:
            return func(username, *args, **kwargs)
        else:
            raise PermissionError(f'User {username} is not logged in')
    return wrapper
Enter fullscreen mode Exit fullscreen mode

When decorated with @authenticate, the function can only be accessed by users in logged_in_users.

Example 4: Memoization Decorator

The memoization decorator caches results of a function to optimize performance for repeated calls with the same arguments.

def memoize(func):
    cache = {}

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

    return wrapper
Enter fullscreen mode Exit fullscreen mode

Functions decorated with @memoize store computed results, returning cached results for identical arguments to avoid redundant calculations.

Using Decorators

@logger
def add(a, b):
    return a + b

@timer
def fibonacci(n):
    if n <= 1:
        return n
    else:
        return fibonacci(n-1) + fibonacci(n-2)

@authenticate
def protected_function(username, message):
    return f'{username}: {message}'

@memoize
def factorial(n):
    if n == 0 or n == 1:
        return 1
    else:
        return n * factorial(n-1)

# Testing each decorated function

print(add(3, 5))  # Output: Calling add with args=(3, 5), kwargs={}, add returned 8, 8

print(fibonacci(10))  # Output: fibonacci took 0.0 seconds to execute, 55

print(protected_function('alice', 'Hello!'))  # Output: alice: Hello!

try:
    print(protected_function('eve', 'Hi!'))  # Raises PermissionError
except PermissionError as e:
    print(e)

print(factorial(5))  # Output: 120

print(factorial(3))  # Output: 6
Enter fullscreen mode Exit fullscreen mode

Each decorator adds specific functionality to the decorated functions:

  • @logger logs function calls and returns.
  • @timer measures execution time.
  • @authenticate restricts function access based on user login.
  • @memoize caches function results to enhance performance.

Python decorators are versatile tools for adding cross-cutting concerns to functions, promoting code reuse and enhancing readability. They are widely used in frameworks and libraries to simplify and extend functionality without modifying core code.

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay