liveBook · Manning

Decorator

As explained in Python How-To

A decorator is a callable that modifies or extends the behavior of another callable or class without changing its underlying definition.

Need to log execution time for several functions? Putting timing code inside each function repeats the same work. A decorator moves that shared behavior into one callable and applies it with `@` above each function definition. The decorated function can keep doing its original job while gaining the extra behavior. section 7.3 section 7.3.1

Listing 7.8 Using a performance-logging decorator
import random
import time


def logging_time(func):
   def logger(*args, **kwargs):
       print(f"--- {func.__name__} starts")
       start_t = time.time()
       value_returned = func(*args, **kwargs)
       end_t = time.time()
       print(f"*** {func.__name__} ends; used time: {end_t - start_t:.2f} s")
       return value_returned

   return logger


@logging_time
def example_func2():
   random_delay = random.randint(3, 5) * 0.1
   time.sleep(random_delay)


example_func2()
# output the following two lines:
--- example_func2 starts
*** example_func2 ends; used time: 0.40 s

The timing example prints a start message, calls the original function, prints elapsed time, and returns the function’s result. section 7.3.1

A function decorator takes a function and returns a replacement callable. Here, the returned inner function closes over `func`, forwards positional and keyword arguments, and returns the original result. Omitting that return would silently change the decorated function’s behavior; defining an inner function with no parameters would fail when the decorated function receives arguments. section 7.3.2

Add a call announcement

```python import functools def announce(func): @functools.wraps(func) def wrapper(*args, **kwargs): print(f"Calling {func.__name__}") return func(*args, **kwargs) return wrapper @announce def add(a, b): return a + b print(add(2, 3)) # Calling add # 5 ``` The announcement lives in one place; `add` still receives its arguments and produces its result. section 7.3.1 section 7.3.2 section 7.3.3

Decoration binds the function’s name to the returned wrapper. Without `functools.wraps(func)`, inspecting `__name__` or `__doc__` can reveal the wrapper’s metadata instead of the original function’s. Use `wraps` on the inner function when defining a function decorator. section 7.3.3 section 7.3.4

Listing 7.9 Wrapping the decorated function
import functools
 
def logging_time_wraps(func):
    @functools.wraps(func)
    def logger(*args, **kwargs):
        """Log the time"""
        print(f"--- {func.__name__} starts")
        start_t = time.time()
        value_returned = func(*args, **kwargs)
        end_t = time.time()
        print(f"*** {func.__name__} ends; used time: 
 {end_t - start_t:.2f} s")
        return value_returned
 
    return logger
 
@logging_time_wraps
def example_wraps():
    """Example function"""
    pass
 
print(example_wraps.__doc__, example_wraps.__name__, sep="; ")
# output: Example function; example_wraps

Compare the wrapper and its printed `__doc__` and `__name__` to see how `functools.wraps` preserves the decorated function’s metadata. section 7.3.3

A decorator can also be a class. Its constructor accepts the function, and an instance’s `__call__` handles later calls; the decorated name then refers to a callable instance rather than a function. A different built-in use, `@dataclass`, uses annotated fields to generate class boilerplate such as `__init__`. For a practical timing exercise, decorate data-manipulation methods and compare CSV-file and SQLite approaches. section 10.5.4 section 9.2.2 section 14.3.7

How Python How-To covers it

How deep it goes
Builds and dissects a function decorator as a closure, including argument forwarding, return values, and metadata preservation; defers full closure theory.
Examples
Demonstrates execution-time logging and metadata inspection, then proposes timing CSV-file and SQLite data operations.
What it assumes
Assumes familiarity with defining and calling Python functions, but introduces decorators and explains their essential closure structure.
What you can do after
Build it from scratch to add reusable logging while preserving arguments, return values, and function metadata.
How it connects
Connects decorators to higher-order functions, closures, callable instances, data classes, and function metadata.

Also explained in

Compare how 7 books explain decorator →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Python How-To. The section links point to the parts of the book it draws on.