Python functools.wraps Function

The functools.wraps function in Python's functools module is a decorator that updates the wrapper function to look more like the wrapped function. This is particularly useful when writing decorators, as it helps preserve the metadata of the original function.

Table of Contents

  1. Introduction
  2. functools.wraps Function Syntax
  3. Examples
    • Basic Usage
    • Using with a Simple Decorator
    • Customizing Attributes
  4. Real-World Use Case
  5. Conclusion

Introduction

When creating decorators, the metadata of the original function (such as its name, docstring, and module) is often lost. The functools.wraps decorator helps copy these attributes from the original function to the wrapper function, making debugging and introspection easier.

functools.wraps Function Syntax

Here is how you use the functools.wraps function:

import functools

@functools.wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, updated=functools.WRAPPER_UPDATES)
def wrapper_decorator(wrapper):
    # Wrapper implementation
    pass

Parameters:

  • wrapped: The original function.
  • assigned: Optional. A tuple specifying which attributes of the original function are assigned directly to the wrapper function (default is functools.WRAPPER_ASSIGNMENTS which includes __module__, __name__, __qualname__, __annotations__, and __doc__).
  • updated: Optional. A tuple specifying which attributes of the wrapper function are updated with the corresponding attributes from the original function (default is functools.WRAPPER_UPDATES which includes __dict__).

Returns:

  • A decorator that updates the wrapper function with the metadata of the wrapped function.

Examples

Basic Usage

Update a simple wrapper function to preserve the metadata of the original function.

Example

import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("Wrapper function")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def my_function():
    """This is my function."""
    print("Original function")

print(my_function.__name__)  # Output: my_function
print(my_function.__doc__)   # Output: This is my function.

Using with a Simple Decorator

Create a decorator that uses functools.wraps to preserve the metadata of the decorated function.

Example

import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("Wrapper function")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def my_function():
    """This is my function."""
    print("Original function")

print(my_function.__name__)  # Output: my_function
print(my_function.__doc__)   # Output: This is my function.

Customizing Attributes

Customize which attributes are updated by wraps.

Example

import functools

def my_decorator(func):
    @functools.wraps(func, assigned=('__doc__',))
    def wrapper(*args, **kwargs):
        print("Wrapper function")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def my_function():
    """This is my function."""
    print("Original function")

print(my_function.__name__)  # Output: wrapper
print(my_function.__doc__)   # Output: This is my function.

Real-World Use Case

Timing Decorator

Create a timing decorator that preserves the metadata of the decorated function.

Example

import functools
import time

def timing_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Execution time: {end_time - start_time} seconds")
        return result
    return wrapper

@timing_decorator
def compute(x, y):
    """Compute the sum of x and y."""
    time.sleep(1)
    return x + y

print(compute(2, 3))         # Output: Execution time: 1.0 seconds
                             #         5
print(compute.__name__)      # Output: compute
print(compute.__doc__)       # Output: Compute the sum of x and y.

Conclusion

The functools.wraps function is used for creating decorators that preserve the metadata of the original function. It helps maintain the integrity of function attributes such as the name, docstring, and module, which is important for debugging and introspection. Proper usage can enhance the readability and maintainability of decorated functions.

Comments

Spring Boot 3 Paid Course Published for Free
on my Java Guides YouTube Channel

Subscribe to my YouTube Channel (165K+ subscribers):
Java Guides Channel

Top 10 My Udemy Courses with Huge Discount:
Udemy Courses - Ramesh Fadatare