🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

شرح مصممو بايثون: الدليل الكامل لعام 2026

⏱️4 min read  ·  822 words


Python Decorators Explained: The Complete 2026 Guide

فريق التحرير في TechPulse
كتاب التكنولوجيا · 24 مايو، 2026
📅 24 مايو 2026⏱ قراءة 14 دقيقة📂 البرمجة🏷 بايثون · مصممو ديكور · متقدم-بايثون

ما هو مصمم بايثون؟

A مصمم بايثونهو نمط تصميم يتيح لك إضافة سلوك جديد إلى وظيفة موجودة – دون لمس رمز الوظيفة. في بايثون، الوظائف هي كائنات من الدرجة الأولى: يمكن تمريرها كوسائط، وتعيينها للمتغيرات، وإعادتها من وظائف أخرى. يستغل مصممو الديكور هذه الخاصية.

|||| بناء الجملة هو مجرد سكر نحوي. عندما تكتب:@📋 نسخ

@my_decorator
def greet(name):
    return f"Hello, {name}!"

📋 نسخ

greet = my_decorator(greet)

يشير الآن إلى النسخة المحسنة.greetمصمم الديكور الأول الخاص بك: خطوة بخطوة

دعونا نبني

بسيطة ديكور قطع الأشجارالذي يطبع رسالة قبل وبعد استدعاء أي وظيفة.📋 نسخ

def log_calls(func):
    """Decorator that logs function entry and exit."""
    def wrapper(*args, **kwargs):
        print(f"→ Calling {func.__name__} with args={args}, kwargs={kwargs}")
        result = func(*args, **kwargs)
        print(f"← {func.__name__} returned {result!r}")
        return result
    return wrapper

@log_calls
def add(a, b):
    return a + b

add(3, 4)
# Output:
# → Calling add with args=(3, 4), kwargs={}
# ← add returned 7

يستقبل

  • log_calls(الوظيفة الأصلية)funcإنه يحدد داخلي
  • يقبلwrapper– لذلك فهو يعمل مع أي توقيع دالة*args, **kwargsالمجمع يستدعي الأصلي
  • ، يلتقط النتيجة ويعيدهاfuncتقوم بإرجاع الغلاف — وليس نتيجة تسميته
  • log_callsإصلاح functools.wraps

هناك خطأ خفي في الديكور أعلاه. بعد الزخرفة

يعودadd.__name__، وليس'wrapper'. هذا يكسر'add'، وآثار المكدس. اصلاحها معhelp(), inspect📋 نسخfunctools.wraps:

import functools

def log_calls(func):
    @functools.wraps(func)   # ← copies __name__, __doc__, __module__, etc.
    def wrapper(*args, **kwargs):
        print(f"→ Calling {func.__name__}")
        result = func(*args, **kwargs)
        print(f"← {func.__name__} returned {result!r}")
        return result
    return wrapper

@log_calls
def add(a, b):
    """Add two numbers."""
    return a + b

print(add.__name__)   # 'add'  ✅
print(add.__doc__)    # 'Add two numbers.'  ✅
استخدم دائمًاداخل كل ديكور تكتبه. يؤدي تخطيه إلى حدوث أخطاء غامضة في التسجيل وأطر الاختبار وأدوات توثيق واجهة برمجة التطبيقات.@functools.wraps(func)ديكورات بالحجج

ماذا لو كنت تريد تكوين الديكور الخاص بك؟ على سبيل المثال،

. أنت بحاجة إلى طبقة إضافية من التداخل —@retry(times=3)مصنع ديكور📋 نسخ:

import functools, time

def retry(times=3, delay=1.0, exceptions=(Exception,)):
    """Retry a function up to `times` times on specified exceptions."""
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            last_err = None
            for attempt in range(1, times + 1):
                try:
                    return func(*args, **kwargs)
                except exceptions as e:
                    last_err = e
                    print(f"   Attempt {attempt}/{times} failed: {e}")
                    if attempt < times:
                        time.sleep(delay)
            raise last_err
        return wrapper
    return decorator

@retry(times=3, delay=0.5, exceptions=(ConnectionError,))
def fetch_data(url):
    # simulate a flaky network call
    raise ConnectionError("timeout")

try:
    fetch_data("https://api.example.com/data")
except ConnectionError:
    print("All retries exhausted.")

. نسميها:retry()decorator()wrapper()يعودretry(times=3)، والذي يأخذdecoratorويعودfuncتكديس ديكورات متعددةwrapper.

يمكنك تطبيق العديد من الديكورات على وظيفة واحدة. يطبقون

من أسفل إلى أعلى(الأعمق أولاً):📋 نسخ

import functools, time

def timer(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        print(f"{func.__name__} took {elapsed:.4f}s")
        return result
    return wrapper

def log_calls(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@timer          # applied second (outer)
@log_calls      # applied first (inner)
def process(n):
    return sum(range(n))

process(1_000_000)
# Output:
# Calling process
# process took 0.0312s

. الترتيب مهم – الديكورات الخارجية تغلف الديكورات الداخلية.process = timer(log_calls(process))مصممو الديكور على أساس الفصل

أي كائن قابل للاستدعاء يمكن أن يكون ديكورًا. يمنحك استخدام الفصل الدراسي الحالة بين المكالمات:

📋 نسخ

import functools

class CallCounter:
    """Counts how many times a function is called."""
    def __init__(self, func):
        functools.update_wrapper(self, func)
        self.func = func
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"{self.func.__name__} called {self.count} time(s)")
        return self.func(*args, **kwargs)

@CallCounter
def say_hello(name):
    print(f"Hello, {name}!")

say_hello("Alice")   # called 1 time(s)
say_hello("Bob")     # called 2 time(s)
print(say_hello.count)  # 2

تأتي Python مع العديد من أدوات الديكور المضمنة التي ستستخدمها باستمرار:

📋 نسخ

class Temperature:
    _kelvin_offset = 273.15

    def __init__(self, celsius):
        self._celsius = celsius

    @property
    def fahrenheit(self):
        """Computed attribute — no () needed when accessing."""
        return self._celsius * 9/5 + 32

    @fahrenheit.setter
    def fahrenheit(self, value):
        self._celsius = (value - 32) * 5/9

    @classmethod
    def from_kelvin(cls, kelvin):
        """Factory method — creates instance from Kelvin."""
        return cls(kelvin - cls._kelvin_offset)

    @staticmethod
    def is_valid_celsius(value):
        """Utility — no access to instance or class."""
        return value >= -273.15

t = Temperature(100)
print(t.fahrenheit)                      # 212.0  (property)
t.fahrenheit = 32                        # setter
t2 = Temperature.from_kelvin(373.15)    # classmethod
print(Temperature.is_valid_celsius(-300))  # False (staticmethod)
الارج الاول الوصول حالة الاستخدام مثيل + فئة
@property self السمات المحسوبة، الحروف/المحددات فئة فقط
@classmethod cls أساليب المصنع، البنائين البديلين لا شيء
@staticmethod ولا وظائف الأداة المساعدة ذات مساحة اسمية للفئة حالات الاستخدام في العالم الحقيقي

تعمل أدوات الديكور على تشغيل معظم أطر عمل بايثون. فيما يلي أنماط درجة الإنتاج:

1. التخزين المؤقت باستخدام ذاكرة التخزين المؤقت LRU

📋 نسخ

from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(50))  # Instant — cached results
print(fibonacci.cache_info())  # CacheInfo(hits=48, misses=51, ...)

📋 نسخ

import functools

def require_auth(func):
    """Decorator for protected routes."""
    @functools.wraps(func)
    def wrapper(request, *args, **kwargs):
        token = request.headers.get("Authorization", "")
        if not token.startswith("Bearer "):
            return {"error": "Unauthorized"}, 401
        return func(request, *args, **kwargs)
    return wrapper

@require_auth
def get_user_profile(request):
    return {"user": "Alice", "email": "alice@example.com"}

📋 نسخ

import functools, time
from collections import defaultdict, deque

def rate_limit(calls=10, period=60):
    """Allow at most `calls` per `period` seconds per caller."""
    history = defaultdict(deque)
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            now = time.time()
            key = args[0] if args else "default"  # use first arg as caller ID
            q = history[key]
            while q and now - q[0] > period:
                q.popleft()
            if len(q) >= calls:
                raise RuntimeError(f"Rate limit exceeded: {calls} calls per {period}s")
            q.append(now)
            return func(*args, **kwargs)
        return wrapper
    return decorator

@rate_limit(calls=5, period=60)
def send_email(user_id, message):
    print(f"Email sent to {user_id}: {message}")

النسيان

  • — فواصل@functools.wrapsوالتتبع وأدوات الاختبارhelp()استدعاء الدالة في جسم الديكور
  • بدلا منreturn wrapper()لا يستخدمreturn wrapper
  • — يكسر أي دالة بمعلمات*args, **kwargsالحالة الافتراضية القابلة للتغيير المشتركة عبر المكالمات
  • — استخدم متغير إغلاق، وليس متغيرًا افتراضيًا قابلاً للتغيير على مستوى الوحدة النمطيةمفقود
  • في المجمعreturn result— يبتلع بصمت القيمة المرجعة للدالة📋 نسخ

# ❌ Wrong — returns None
def broken(func):
    def wrapper(*args, **kwargs):
        func(*args, **kwargs)   # no return!
    return wrapper

# ✅ Correct
def fixed(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)  # always return
    return wrapper

الآن بعد أن فهمت مصممي الديكور، استكشف كيفية تشغيل أطر العمل مثل

هيكلة مشاريع بايثونوالأنماط المتقدمة. تحقق من دليلنا علىتعبيرات بايثون المختصرةلمزيد من الحيل رمز بايثونيك.الأسئلة المتداولة

ما هو مصمم بايثون؟

مصمم الديكور في Python هو دالة تأخذ وظيفة أخرى كمدخلات وترجع نسخة محسنة – دون تعديل النسخة الأصلية.

بناء الجملة هو اختصار لـ@متى يجب أن أستخدم أدوات الديكور؟func = decorator(func).

استخدم أدوات الديكور للمخاوف الشاملة: التسجيل، والتخزين المؤقت، والمصادقة، وتحديد المعدل، والتوقيت، والتحقق من صحة الإدخال – أي سلوك تريد تطبيقه على وظائف متعددة دون تكرار التعليمات البرمجية.

ماذا يفعل functools.wraps؟

يقوم بنسخ الوظيفة الأصلية

It copies the original function’s__name__, __doc__والسمات الأخرى للمجمّع، مع الحفاظ على الهوية لتصحيح الأخطاء، والمساعدة () وأدوات الاختبار.

هل يمكن لمصممي الديكور أن يكون لديهم حجج؟

نعم. أضف دالة مصنع خارجية تقبل الوسائط وتعيد الديكور الحقيقي. النمط:@retry(times=3)retry()إرجاع الديكور.

ما الفرق بين @staticmethod و@classmethod؟

@staticmethodلا يحصل على أي وسيطة أولى ضمنية – إنها وظيفة عادية في مساحة اسم الفئة.@classmethodيتلقى الفئة (cls) كوسيطة أولى، وهي مفيدة لطرق المصنع.

كيف تعمل الديكورات المكدسة؟

من أسفل إلى أعلى: مصمم الديكور الأقرب إلىdefيتم تطبيقه أولا.@A @B def f()يساويf = A(B(f)).

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা