> ## Documentation Index
> Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Python Function Decorator

A Python function decorator is a callable (such as a function or a class implementing the `__call__` method) that takes another callable as an argument, dynamically modifies or extends its execution context, and returns an object. While decorators frequently wrap the target function within a closure to return a new callable, they can also return the original, unmodified function (e.g., for registration purposes) or a non-callable object (e.g., a descriptor object like `@property`).

## Syntactic Sugar vs. Manual Application

The `@` symbol is syntactic sugar for passing a function into the decorator and reassigning the resulting object back to the original function name.

The following two implementations are strictly equivalent at runtime:

**Using Syntactic Sugar:**

```python theme={"dark"}
def my_decorator(func):
    return func

@my_decorator
def target_function():
    pass
```

**Manual Application:**

```python theme={"dark"}
def my_decorator(func):
    return func

def target_function():
    pass

target_function = my_decorator(target_function)
```

## Standard Decorator Architecture

A standard function-based decorator consists of an outer function that accepts the target function, and an inner function (the wrapper) that executes the extended logic. The wrapper utilizes `*args` and `**kwargs` to maintain compatibility with any arbitrary signature the target function might possess.

```python theme={"dark"}
def standard_decorator(func):
    def wrapper(*args, **kwargs):
        # Pre-execution logic
        
        # Execute the original function
        result = func(*args, **kwargs)
        
        # Post-execution logic
        return result
        
    return wrapper
```

## Preserving Function Metadata

By default, returning a wrapper function replaces the original function's metadata (such as `__name__`, `__doc__`, and `__module__`) with the metadata of the wrapper itself. To preserve the target function's identity, the standard library provides `functools.wraps`, which is applied as a decorator to the inner wrapper function.

```python theme={"dark"}
import functools

def metadata_preserving_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result
    return wrapper

@metadata_preserving_decorator
def example_function():
    """This docstring is preserved."""
    pass


# example_function.__name__ remains 'example_function'

# example_function.__doc__ remains 'This docstring is preserved.'
```

## Decorator Stacking (Chaining)

Multiple decorators can be applied to a single function by stacking them. The critical mechanism to understand in stacking is the difference between the order of application and the order of execution.

Decorators are **applied bottom-up** (closest to the function definition first). However, the execution of the resulting wrappers is **nested**. The pre-execution logic runs **outside-in (top-down)**, while the post-execution logic runs **inside-out (bottom-up)** as the call stack unwinds.

```python theme={"dark"}
def decorator_one(func):
    def wrapper(*args, **kwargs):
        print("Entering decorator_one")
        result = func(*args, **kwargs)
        print("Exiting decorator_one")
        return result
    return wrapper

def decorator_two(func):
    def wrapper(*args, **kwargs):
        print("Entering decorator_two")
        result = func(*args, **kwargs)
        print("Exiting decorator_two")
        return result
    return wrapper

@decorator_one
@decorator_two
def stacked_function():
    print("Executing target function")


# Application equivalent: 

# stacked_function = decorator_one(decorator_two(stacked_function))

stacked_function()

# Output:

# Entering decorator_one

# Entering decorator_two

# Executing target function

# Exiting decorator_two

# Exiting decorator_one
```

## Class-Based Decorators

Decorators can also be implemented as classes, a pattern highly effective for decorators requiring complex state management. A standard class-based decorator without arguments accepts the target function in its `__init__` method and implements the wrapper logic in its `__call__` method.

To preserve the original function's metadata, `functools.update_wrapper` must be explicitly called within `__init__`. Furthermore, if a class-based decorator is applied to a class method, it will break by default. Because the decorator class does not inherently implement the descriptor protocol, the decorated method loses its binding to the instance, meaning `self` will not be passed during invocation. This is resolved by implementing the `__get__` method to return a bound method.

```python theme={"dark"}
import functools
import types

class ClassDecorator:
    def __init__(self, func):
        self.func = func
        self.call_count = 0  # State management
        # Preserve original function's metadata
        functools.update_wrapper(self, func)

    def __call__(self, *args, **kwargs):
        self.call_count += 1
        # Pre-execution logic
        result = self.func(*args, **kwargs)
        # Post-execution logic
        return result

    def __get__(self, instance, owner):
        if instance is None:
            return self
        # Implement descriptor protocol to bind the method to the instance
        return types.MethodType(self, instance)

@ClassDecorator
def standalone_function():
    pass

class ExampleClass:
    @ClassDecorator
    def method(self):
        pass
```

## Decorator Factories (Decorators with Arguments)

When a decorator requires its own arguments, it must be implemented as a decorator factory. For function-based decorators, this requires a three-level nested architecture:

1. The outermost function accepts the decorator arguments.
2. The middle function accepts the target callable.
3. The innermost function (the wrapper) accepts the target callable's arguments.

```python theme={"dark"}
import functools

def decorator_factory(decorator_arg1, decorator_arg2):
    def actual_decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # Logic utilizing decorator_arg1 and decorator_arg2
            
            result = func(*args, **kwargs)
            return result
        return wrapper
    return actual_decorator

@decorator_factory("value1", "value2")
def target_function(x, y):
    return x + y
```

In this architecture, the Python interpreter first evaluates `decorator_factory("value1", "value2")`, which returns `actual_decorator`. The interpreter then applies `actual_decorator` to `target_function`.

<div
  style={{ 
display: "flex", 
justifyContent: "space-between", 
alignItems: "center", 
maxWidth: "754px", 
padding: "1rem 0",
marginBottom: "24px"
}}
>
  <span style={{ fontWeight: "bold", fontSize: "1.25rem", color: "var(--tw-prose-headings)", fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif" }}>Tired of Poor Python Skills? Fix That With Deep Grasping!</span>

  <a
    href="https://syntblaze.com"
    target="_blank"
    style={{ 
  marginLeft: "24px",
  textDecoration: "none", 
  backgroundColor: "#007AFF",
  color: "#ffffff", 
  padding: "6px 16px", 
  borderRadius: "16px",
  fontSize: "0.9rem",
  fontWeight: "600",
  textAlign: "center",
  transition: "background-color 0.2s ease"
}}
  >
    Learn More
  </a>
</div>

<div style={{ display: "flex", gap: "12px", flexWrap: "wrap" }}>
  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/skill-tracking.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=b9b0305c93bb501c9e767b5c76c88835" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/skill-tracking.png" />

  <img src="https://mintcdn.com/syntblazellc/23tyuOzaWS88qFlc/images/nuggets.png?fit=max&auto=format&n=23tyuOzaWS88qFlc&q=85&s=c86c80197299762989e9b882419b2109" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/nuggets.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/bite-sized-exercises.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=a65f9a38c37ff28ab73ed783c53c60e3" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/bite-sized-exercises.png" />
</div>

<div style={{ display: "flex", gap: "12px", flexWrap: "wrap", marginTop: "12px" }}>
  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/mastery-chain.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=748a1763454713e679260fbb95f154a2" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/mastery-chain.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/element-previews.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=242f61448ff5dd6deaaab2dccc13b507" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/element-previews.png" />

  <img src="https://mintcdn.com/syntblazellc/-L0ums_2lctDSZ1l/images/element-explanations.png?fit=max&auto=format&n=-L0ums_2lctDSZ1l&q=85&s=cf0fc1c31f9cd0fc26716781be05fbc9" style={{ width: "30%", minWidth: 60 }} width="621" height="1344" data-path="images/element-explanations.png" />
</div>
