0Pricing
Python Academy · درس

كتابة مزخرفات مخصصة

أنشئ مزخرفات باستخدام دوال التغليف وfunctools.wraps

كتابة مزخرفات مخصصة درس مجاني في Python Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Python Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Python Academy 4 دروس في المجموع.

مقدمة

المزيّنات هي دوال تغلّف دوالًا أخرى، فتضيف سلوكًا قبل التنفيذ أو بعده من دون تعديل الدالة الأصلية.

ما المزيّن؟

يُعد ‎@decorator‎ الموضوع فوق دالة صياغة مختصرة للتعبير: ‎func = decorator(func)‎. إذ يستقبل المزيّن الدالة ويُرجع دالة تغليف.
def shout(func):
    def wrapper(*a, **kw):
        result = func(*a, **kw)
        return str(result).upper()
    return wrapper
@shout
def greet(name): return f'hello {name}'
print(greet('Alice'))

نمط التغليف

تملك دالة التغليف التوقيع نفسه للدالة الأصلية. وتستدعي الدالة الأصلية بداخلها، مع إضافة السلوك حولها.
def timer(func):
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f'{func.__name__} took {time.time()-start:.4f}s')
        return result
    return wrapper
@timer
def slow(): import time; time.sleep(0.01)
slow()

‎functools.wraps‎

يحافظ ‎@wraps(func)‎ الموضوع على دالة التغليف على ‎__name__‎ و‎__doc__‎ و‎__annotations__‎ الخاصة بالدالة الأصلية.
from functools import wraps
def log(func):
    @wraps(func)
    def wrapper(*a, **kw):
        print(f'calling {func.__name__}')
        return func(*a, **kw)
    return wrapper
@log
def add(a, b): return a + b
print(add.__name__)
add(1, 2)

مزيّن بوسائط

يحتاج المزيّن الذي يستقبل وسائط إلى مستوى إضافي من التغليف: دالة مصنع تستقبل الوسائط وتُرجع المزيّن.
def repeat(n):
    def decorator(func):
        from functools import wraps
        @wraps(func)
        def wrapper(*a, **kw):
            for _ in range(n): func(*a, **kw)
        return wrapper
    return decorator
@repeat(3)
def hi(): print('hi')
hi()

تكديس المزيّنات

تُكدّس المزيّنات المتعددة من الأسفل إلى الأعلى: يعني ‎@d2 @d1‎ أن ‎func = d2(d1(func))‎. ويُنفَّذ المزيّن الخارجي، الموجود في الأعلى، أخيرًا.
def bold(f):
    from functools import wraps
    @wraps(f)
    def w(*a,**k): return '<b>' + f(*a,**k) + '</b>'
    return w
def italic(f):
    from functools import wraps
    @wraps(f)
    def w(*a,**k): return '<i>' + f(*a,**k) + '</i>'
    return w
@bold
@italic
def text(): return 'hello'
print(text())

مزيّن قائم على فئة

يمكن لفئة تملك ‎__call__‎ أن تكون مزيّنًا. وتخزّن الحالة بين الاستدعاءات.
class Counter:
    def __init__(self, func): self.func,self.count=func,0
    def __call__(self, *a, **kw):
        self.count+=1
        return self.func(*a, **kw)
@Counter
def greet(name): return f'hi {name}'
greet('Alice'); greet('Bob')
print(greet.count)

مزيّن الحفظ المؤقت

خزّن النتائج السابقة لتجنب إعادة الحساب: ‎if args in cache: return cache[args]‎. وتنفذ ‎functools.lru_cache‎ ذلك مضمّنًا.
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
    if n < 2: return n
    return fib(n-1) + fib(n-2)
print(fib(30))

مزيّن التفويض

تشيع المزيّنات للتحكم في الوصول: تحقّق من تسجيل دخول المستخدم قبل تشغيل الدالة.
def requires_auth(func):
    from functools import wraps
    @wraps(func)
    def wrapper(user, *a, **kw):
        if not user.get('authenticated'):
            raise PermissionError('Not authenticated')
        return func(user, *a, **kw)
    return wrapper
@requires_auth
def dashboard(user): return 'Welcome!'
try: dashboard({'authenticated': False})
except PermissionError as e: print(e)

مزيّن إعادة المحاولة

غلّف دالة لإعادة المحاولة عند الفشل: ‎for _ in range(retries): try: return func() except Exception: pass‎
import random
from functools import wraps
def retry(times=3):
    def dec(func):
        @wraps(func)
        def wrapper(*a, **kw):
            for i in range(times):
                try: return func(*a, **kw)
                except Exception as e:
                    if i==times-1: raise
        return wrapper
    return dec
@retry(3)
def flaky():
    if random.random()<0.7: raise ValueError
    return 'ok'
try: print(flaky())
except ValueError: print('failed')

أفضل ممارسات المزيّنات

استخدم دائمًا ‎@functools.wraps‎. اجعل كل مزيّن مخصصًا لغرض واحد. وثّق ما يضيفه. واختبر المزيّن منفصلًا عن الدالة المزيّنة.
from functools import wraps
def validate_positive(func):
    @wraps(func)
    def wrapper(x, *a, **kw):
        if x <= 0: raise ValueError(f'{x} must be positive')
        return func(x, *a, **kw)
    return wrapper
@validate_positive
def sqrt(x): return x**0.5
print(sqrt(9))

تحقق سريع

ماذا يفعل ‎@functools.wraps(func)‎ عند تطبيقه على دالة تغليف؟

مراجعة

المزيّنات: ‎func = decorator(func)‎. استخدم ‎wrapper(*args, **kwargs)‎. يحافظ ‎@wraps‎ على البيانات الوصفية. تضيف المزيّنات ذات الوسائط مستوى إضافيًا. ويمكن تكديسها باستخدام عدة ‎@decorators‎.

واصل التقدم

تقدم ممتاز! واصل التقدم لإتقان المفهوم التالي.

الأسئلة الشائعة

هل درس «كتابة مزخرفات مخصصة» مجاني؟

نعم — نص درس «كتابة مزخرفات مخصصة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Python Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Python Academy 4 دروس في المجموع.

ماذا ستتعلم في «كتابة مزخرفات مخصصة»؟

أنشئ مزخرفات باستخدام دوال التغليف وfunctools.wraps تتمرن على Python Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Python Academy؟

لا تُشترط خبرة سابقة. Python Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «كتابة مزخرفات مخصصة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Python Academy هذا؟

نعم. كل درس في Python Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. الدوال ككائنات من الدرجة الأولى
  2. كتابة مزخرفات مخصصة
  3. المزخرف @property
  4. @classmethod و@staticmethod
← العودة إلى Python Academy