> ## 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 Class Decorator

A class decorator is a higher-order callable (such as a function or a class) that takes a class object as its single argument and returns a replacement object. While it typically returns a modified class or a proxy class, a class decorator can return any Python object, including a function or an instance of another class. It provides a metaprogramming mechanism to modify class behavior, attributes, or methods at the time of class definition, operating at the class level rather than the instance level.

## Syntax and Desugaring

The `@` symbol is syntactic sugar applied directly above the `class` keyword.

```python theme={"dark"}
@decorator
class TargetClass:
    pass
```

At runtime, the Python interpreter desugars this syntax into a standard function call, reassigning the class name in the local namespace to the return value of the decorator:

```python theme={"dark"}
class TargetClass:
    pass

TargetClass = decorator(TargetClass)
```

## Implementation Patterns

Class decorators generally follow one of three architectural patterns depending on whether they mutate the original class, wrap it in a proxy, or use a callable instance to replace the class.

### 1. Mutation (Returning the Original Class)

The decorator modifies the target class's namespace (e.g., injecting attributes or overriding methods) and returns the original class object. This preserves the class identity, meaning `isinstance()` and `issubclass()` checks remain unaffected.

```python theme={"dark"}
def mutate_class(cls):
    # Inject a new method into the class dictionary
    def new_method(self):
        return "Injected"
    
    setattr(cls, 'injected_method', new_method)
    return cls

@mutate_class
class BaseClass:
    pass
```

### 2. Wrapping (Returning a Proxy Class)

The decorator returns a completely new class that intercepts instantiation or attribute access. This pattern replaces the original class in the local namespace.

```python theme={"dark"}
def wrap_class(cls):
    class Wrapper:
        def __init__(self, *args, **kwargs):
            # Intercept instantiation
            self._wrapped_instance = cls(*args, **kwargs)

        def __getattr__(self, name):
            # Delegate attribute access to the original instance
            return getattr(self._wrapped_instance, name)
            
    return Wrapper

@wrap_class
class BaseClass:
    pass
```

*Note on Type Checking:* Because `BaseClass` is now a reference to `Wrapper`, standard type checking (`type(obj) is BaseClass`) will evaluate against `Wrapper`, not the original class.

*Note on Magic Methods:* A major limitation of this proxy wrapping pattern is that `__getattr__` will not delegate special/magic methods (e.g., `__str__`, `__len__`, `__iter__`). Python's data model dictates that special methods are looked up directly on the class (`Wrapper`), bypassing `__getattr__`. Consequently, the wrapped instance's magic methods will not be accessible unless explicitly redefined on the `Wrapper` class.

### 3. Class-Based Class Decorators

A class can act as a decorator for another class. To achieve this, the decorator class must implement `__init__` to accept the target class, and `__call__` to handle the instantiation of the decorated class.

```python theme={"dark"}
class DecoratorClass:
    def __init__(self, cls):
        self._cls = cls

    def __call__(self, *args, **kwargs):
        # Execute logic prior to target class instantiation
        instance = self._cls(*args, **kwargs)
        # Execute logic post-instantiation
        return instance

@DecoratorClass
class TargetClass:
    pass
```

*Critical Limitation:* In this pattern, `TargetClass` is reassigned to an instance of `DecoratorClass`, meaning it is no longer a type. Consequently, using it in standard type checks like `isinstance(obj, TargetClass)` or `issubclass(cls, TargetClass)` will raise a `TypeError: isinstance() arg 2 must be a type`. This is a fundamental breakage of class semantics that must be accounted for when using instances as class decorators.

## Parameterized Class Decorators (Decorator Factories)

To pass arguments to a class decorator, you must create a decorator factory—a function that accepts the parameters and returns the actual decorator callable.

```python theme={"dark"}
def decorator_factory(param1, param2):
    def actual_decorator(cls):
        setattr(cls, 'meta_data', (param1, param2))
        return cls
    return actual_decorator

@decorator_factory("value1", "value2")
class TargetClass:
    pass
```

This desugars to a chained call:

```python theme={"dark"}
TargetClass = decorator_factory("value1", "value2")(TargetClass)
```

## Execution Timing

Class decorators are evaluated and executed exactly once: at module import time (or when the script is parsed and executed). The decorator logic runs immediately after the class body is evaluated and the class object is constructed by its metaclass, but *before* any instances of the class are created.

<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>
