0%

🪄 The Symbol Of Power: @

In Python, @ before a function is a decorator, a wrapper function. It takes your function, runs extra code before or after it, and then returns the result.
🔮 @logtime def brew(): print(“brewing…”)

A single symbol. The at sign. @. In Python, it is not just an ornament. It transforms how a function behaves without touching the function itself. A decorator wraps around your function like a cloak. It adds power before and after the original spell. The original code remains untouched. Pure. Clean. Unchanged.

🕯️ Magic Note

Decorators are functions that take another function as input and return a new function. The @decorator_name syntax is just sugar for function = decorator_name(function). Python applies the decorator at definition time, not at call time.

The syntax @logtime above def brew() means “pass the brew function through the logtime decorator before using it.” The decorator typically adds logging, timing checks, authentication, or validation. Your function runs exactly as written, but with extra powers wrapped around it.
  • Decorators are applied at definition time, not runtime
  • Multiple decorators stack: @timer @log def func() applies from bottom to top
  • Decorators can accept arguments with nested functions
  • Common uses: @staticmethod, @classmethod, @property, @cache
💡 To create your own decorator, define a function that takes a function, defines a wrapper inside, and returns the wrapper. Use @functools.wraps on your wrapper to preserve the original function’s name and docstring. This makes debugging much easier.
DecoratorPurposeExample
@staticmethodMethod without selfInside classes
@classmethodMethod receives classAlternative constructors
@propertyMethod acts as attributeComputed values
@lru_cacheCache repeated callsExpensive computations
@timerMeasure execution timePerformance debugging
⚠️ Decorators execute when the function is defined, not just when it is called. This means side effects inside a decorator (like print statements or file writes) happen at module import time. Also, be careful with decorator order. The one closest to the function runs first on the way in, last on the way out.
Examples

Python

# Creating a simple timing decorator

import time

def logtime(func):

def wrapper(*args, **kwargs):

start = time.time()

result = func(*args, **kwargs)

end = time.time()

print(f”⏱ {end – start:.3f}s”)

return result

return wrapper

Python

# Using the @logtime decorator

@logtime

def brew():

print(“brewing…”)

time.sleep(0.002)

brew()

# Output: brewing…

# Output: ⏱ 0.002s

Python

# Multiple decorators stacking

@logtime

@authenticate

def secret_spell():

return “✨”

# authenticate runs first on the way in

# logtime wraps everything including authenticate

Common Mistakes
  • Forgetting that decorators run at definition time, causing confusion about print statements appearing at import
  • Stacking decorators in the wrong order, thinking they run from top to bottom when they wrap from bottom to top
  • Not using @functools.wraps inside custom decorators, losing the original function’s metadata for debugging

⚡ Whisper

The at sign is not just decoration. It is a gate. Your function enters. Magic happens around it. The function emerges unchanged but surrounded by power. This is the symbol of transformation without touch.