محتويات الدورة

بايثون / أنظمة قابلة للصيانة / الدرس 15

المزخرفات وسياقات الموارد

غلّف السلوك دون فقد عقد الدالة، وعبر عن اكتساب الموارد وتنظيفها بحدود سياق موثوقة.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • الدوال قيم عادية
  • تركيب الأعمار عن قصد

الدوال قيم عادية

يمكن تمرير الدالة وتخزينها وإعادتها مثل القيم. يستقبل المزخرف كائنا قابلا للاستدعاء ويعيد بديلا، غالبا غلافا يضيف سلوكا قبل تمرير الاستدعاء أو بعده. تطبق @decorator التحويل عند تنفيذ التعريف. يحتفظ الإغلاق بالدالة الأصلية وإعداداتها. وضح عمر الحالة؛ فقد يستمر عداد أو مخزن مؤقت داخل الإغلاق بين الاستدعاءات ويحتاج إلى حدود أو مزامنة. يجب حفظ النتيجة والفشل الموثقين إلا إذا كان تغييرهما غرضا صريحا.

حفظ البيانات الوصفية وسلوك الوسائط

يقبل الغلاف الشفاف عادة *args و**kwargs ويمررهما. تنسخ functools.wraps بيانات مفيدة وتضبط __wrapped__ للفحص والتوثيق، لكنها لا تحفظ كل المعاني ولا تجعل غلافا متزامنا مناسبا تلقائيا لدالة async أو مولد. تعيد المحاولة الآثار الجانبية وقد تغير التوقيت، فتحتاج سياسة مبررة. تجنب كشف الوسائط الحساسة في السجل. تتطلب مفاتيح التخزين المؤقت قيما ثابتة قابلة للتجزئة، وقد تصبح النتائج قديمة أو مشتركة قابلة للتعديل. تتطلب هذه السلوكيات مراجعة لأنها تؤثر في استدعاءات كثيرة.

غلاف صغير واضح

يضيف المثال إشعار استدعاء محددا ويمرر الوسائط والنتيجة ويحفظ الاسم. غرضه الملاحظة، ولا يبتلع الأخطاء أو يغير الناتج. تناسب الطباعة العرض التعليمي، ويستخدم التطبيق عادة سجلا مضبوطا بحقول آمنة. يعيد الغلاف نتيجة الدالة ولا يكتفي باستدعائها. يؤدي نسيان return إلى تحويل كل نجاح إلى None وقد يسبب TypeError بعيدة. يكشف اختبار النتيجة والاسم تراجع العقد والفحص معا.

python غلاف صغير واضح — مثال محلول
from functools import wraps

def announce(function):
    @wraps(function)
    def wrapper(*args, **kwargs):
        print("calling", function.__name__)
        return function(*args, **kwargs)
    return wrapper

@announce
def double(value):
    return value * 2

print(double(6))
print(double.__name__)
الناتج المتوقع
calling double
12
double

يسبق الإشعار الاستدعاء الأصلي. تحفظ إعادة النتيجة العدد 12 وتحفظ wraps الاسم double.

مدير السياق يملك عمرا

يحدد مدير السياق الدخول والخروج حول with. يمكن تنفيذ __enter__ و__exit__ أو استخدام contextlib.contextmanager لمولد يعطي قيمة مرة واحدة. تسبق التهيئة yield وينفذ الجسم أثناء التعليق، ويوضع التنظيف في finally بعدها. يعاد إدخال استثناء الجسم عند نقطة yield؛ يؤدي التقاطه دون إعادة رفعه إلى إخفائه. يدير المثال مخزنا نصيا في الذاكرة ويثبت إغلاقه بعد الخروج دون ملفات خارجية. يختلف تحرير المورد عن التراجع التجاري؛ فلا يلغي إغلاق الملف بايتات كُتبت بالفعل.

python مدير السياق يملك عمرا — مثال محلول
from contextlib import contextmanager
from io import StringIO

@contextmanager
def text_buffer():
    buffer = StringIO()
    try:
        yield buffer
    finally:
        buffer.close()

with text_buffer() as buffer:
    buffer.write("ready")
    print(buffer.getvalue())
print(buffer.closed)
الناتج المتوقع
ready
True

يستخدم الجسم المخزن المفتوح، ثم يستأنف الخروج المولد إلى finally ويؤكد المرجع المحتفظ به إغلاق المورد.

تركيب الأعمار عن قصد

تدعم ExitStack عددا متغيرا من مديري السياق وتفك التنظيف بعكس الترتيب. تفيد للموارد المختارة ديناميكيا، بينما تكفي with المتداخلة لمجموعة صغيرة ثابتة. قد يفشل التنظيف نفسه، فاحفظ سياقا يفسر المشكلة الأصلية وفشل التحرير. اختبر النجاح وفشل الجسم وفشل الاكتساب وإعادة الاستخدام إذا وُعد بها. ينشئ مصنع السياق المبني على مولد مديرا جديدا لكل استدعاء؛ لا تفترض إعادة استخدام النسخة الواحدة. استخدم السياقات غير المتزامنة لموارد async بدلا من حجب حلقة الأحداث بعمل متزامن.

الأخطاء الشائعة وإصلاحها

إرجاع دالة مزخرفة None بصورة مفاجئة

لماذا يحدث؟
مرر الغلاف الاستدعاء لكنه حذف return.
كيف تصلحه؟
أعد نتيجة الدالة المغلفة صراحة.
كيف تتجنب تكراره؟
اختبر القيمة المعادة من الاستدعاء المغلف.

إخفاء الغلاف اسم الدالة المفيد

لماذا يحدث؟
استبدلت بيانات الغلاف بيانات الدالة.
كيف تصلحه؟
طبق functools.wraps على الغلاف.
كيف تتجنب تكراره؟
افحص البيانات الوصفية عندما تعتمد عليها الأدوات.

اختفاء استثناء داخل with

لماذا يحدث؟
التقط مدير السياق الاستثناء دون إعادة رفعه.
كيف تصلحه؟
استخدم finally للتنظيف وأعد رفع غير المتوقع.
كيف تتجنب تكراره؟
اختبر الخروج الاستثنائي والإغلاق الطبيعي.

اختبر فهمك

1. ما الذي يجعل مزخرف إعادة المحاولة خطرا لعملية إرسال فاتورة؟

اعرض الحل المشروح

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

2. كيف تتحقق من التنظيف عند رفع جسم with استثناء؟

اعرض الحل المشروح

أنشئ موردا اختباريا قابلا للملاحظة، وادخل مديره وارفع استثناء معروفا والتقطه خارج السياق. أكد انتشار الاستثناء الأصلي وإغلاق المورد. هذان وعدان مستقلان؛ فرؤية الاستثناء وحدها لا تثبت التنظيف.

أهم ما تعلمته

  • يحفظ الغلاف عقد الاستدعاء المقصود.
  • تحفظ wraps البيانات الوصفية لا كل المعاني.
  • توضح مديرات السياق عمر المورد.

المراجع الرسمية