تعد أدوات تزيين بايثون من أكثر ميزات اللغة أناقة. في عام 2026، أصبحت أدوات الديكور موجودة في كل مكان – بدءًا من تعريفات مسار FastAPI وحتى فئات البيانات، ومن التحقق من النوع إلى التخزين المؤقت وإعادة المحاولة المنطقية. يأخذك هذا الدليل الكامل من الأساسيات إلى إنشاء ديكورات خاصة بك على مستوى الإنتاج.
📋 Table of Contents
ما هو الديكور؟
المزخرف هو دالة تغلف دالة أخرى لإضافة سلوك. ال@بناء الجملة هو السكر النحوي:
# These two are equivalent:
@my_decorator
def my_function():
pass
# Same as:
def my_function():
pass
my_function = my_decorator(my_function)
# Simple decorator example
def log_calls(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
result = func(*args, **kwargs)
print(f"Done {func.__name__}")
return result
return wrapper
@log_calls
def greet(name: str) -> str:
return f"Hello, {name}!"
greet("Alice")
# Calling greet
# Done greet
functools.wraps — الحفاظ على البيانات الوصفية
import functools
def my_decorator(func):
@functools.wraps(func) # preserves __name__, __doc__, __annotations__
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@my_decorator
def add(a: int, b: int) -> int:
return a + b
print(add.__name__) # "add" (without wraps, would be "wrapper")
print(add.__doc__) # preserved docstring
ديكور مع الحجج
import functools, time
# Decorator that accepts arguments uses three levels of nesting
def retry(max_attempts: int = 3, delay: float = 1.0, exceptions: tuple = (Exception,)):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
last_error = None
for attempt in range(1, max_attempts + 1):
try:
return func(*args, **kwargs)
except exceptions as e:
last_error = e
if attempt < max_attempts:
print(f"Attempt {attempt} failed: {e}. Retrying in {delay}s...")
time.sleep(delay)
raise last_error
return wrapper
return decorator
@retry(max_attempts=3, delay=0.5, exceptions=(ConnectionError, TimeoutError))
def fetch_data(url: str) -> dict:
import requests
return requests.get(url, timeout=5).json()
مصممو الديكور على أساس الفصل
import functools
import time
from collections import defaultdict
class RateLimit:
def __init__(self, calls: int, period: float):
self.calls = calls
self.period = period
self._call_times: list[float] = []
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
now = time.time()
# Remove calls older than period
self._call_times = [t for t in self._call_times if now - t < self.period]
if len(self._call_times) >= self.calls:
wait_time = self.period - (now - self._call_times[0])
if wait_time > 0:
time.sleep(wait_time)
self._call_times.append(time.time())
return func(*args, **kwargs)
return wrapper
@RateLimit(calls=5, period=1.0) # max 5 calls per second
def api_request(endpoint: str) -> dict:
import requests
return requests.get(f"https://api.example.com{endpoint}").json()
التخزين المؤقت للديكور
from functools import lru_cache, cache
import time
# Simple memoization (Python 3.9+)
@cache # unlimited cache size
def fibonacci(n: int) -> int:
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# LRU cache with size limit
@lru_cache(maxsize=128)
def expensive_computation(x: float, y: float) -> float:
time.sleep(0.1) # simulate slow computation
return x ** 2 + y ** 2
# Cache with expiry (custom implementation)
def ttl_cache(ttl_seconds: float):
def decorator(func):
cache_store: dict = {}
cache_times: dict = {}
@functools.wraps(func)
def wrapper(*args, **kwargs):
key = (args, tuple(sorted(kwargs.items())))
now = time.time()
if key in cache_store and (now - cache_times[key]) < ttl_seconds:
return cache_store[key] # return cached
result = func(*args, **kwargs)
cache_store[key] = result
cache_times[key] = now
return result
return wrapper
return decorator
@ttl_cache(ttl_seconds=60)
def get_exchange_rate(currency: str) -> float:
# Fetches rate from API, cached for 60 seconds
...
# Inspect cache stats
print(fibonacci.cache_info()) # CacheInfo(hits=5, misses=10, maxsize=None, currsize=10)
fibonacci.cache_clear()
الديكور في FastAPI
from fastapi import FastAPI, Depends, HTTPException, Request
from functools import wraps
import time
app = FastAPI()
# FastAPI uses decorators for routing
@app.get("/users/{user_id}")
async def get_user(user_id: int):
return {"id": user_id}
# Custom decorator for timing API endpoints
def measure_time(func):
@wraps(func)
async def wrapper(*args, **kwargs):
start = time.perf_counter()
response = await func(*args, **kwargs)
duration = time.perf_counter() - start
print(f"{func.__name__}: {duration*1000:.2f}ms")
return response
return wrapper
@app.get("/expensive")
@measure_time
async def expensive_endpoint():
import asyncio
await asyncio.sleep(0.1)
return {"status": "done"}
# Require auth decorator
def require_auth(func):
@wraps(func)
async def wrapper(request: Request, *args, **kwargs):
token = request.headers.get("Authorization", "").replace("Bearer ", "")
if not token or not validate_token(token):
raise HTTPException(status_code=401, detail="Unauthorized")
return await func(request, *args, **kwargs)
return wrapper
أنماط الديكور الشائعة
import functools, time, logging
logger = logging.getLogger(__name__)
# Timing decorator
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
logger.debug(f"{func.__name__} took {elapsed*1000:.2f}ms")
return result
return wrapper
# Validation decorator
def validate_positive(func):
@functools.wraps(func)
def wrapper(value: float, *args, **kwargs):
if value < 0:
raise ValueError(f"Expected positive number, got {value}")
return func(value, *args, **kwargs)
return wrapper
# Singleton decorator
def singleton(cls):
instances = {}
@functools.wraps(cls)
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class DatabaseConnection:
def __init__(self, url: str):
self.url = url
# Deprecation warning
def deprecated(reason: str = ""):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
import warnings
msg = f"{func.__name__} is deprecated. {reason}"
warnings.warn(msg, DeprecationWarning, stacklevel=2)
return func(*args, **kwargs)
return wrapper
return decorator
@deprecated("Use new_function() instead")
def old_function():
pass
التراص الديكور
# Decorators apply bottom-to-top
@retry(max_attempts=3)
@timer
@validate_positive
def compute(value: float) -> float:
return value ** 2
# Equivalent to:
compute = retry(max_attempts=3)(timer(validate_positive(compute)))
تعد أدوات تزيين Python هي الطريقة الأنظف لإضافة اهتمامات شاملة مثل التسجيل والتخزين المؤقت وتحديد المعدل والمصادقة وإعادة المحاولة المنطقية دون تعديل الوظيفة الأساسية. استخدم دائما@functools.wrapsللحفاظ على البيانات الوصفية. أنشئ ديكورات ذات معلمات عندما تحتاج إلى سلوك قابل للتكوين.
🔗 Share this article
✍️ Leave a Comment