AzLearn

مدراء السياق

Context Managers

مفهوم ~20 دقيقة

مدراء السياق — Context Managers

سبق أن استخدمت with open("file.txt") as f: دون التفكير كثيراً في ما يجري خلف الكواليس. with ليست مجرد اختصار — إنها آلية تضمن تنفيذ كود التنظيف (إغلاق ملف، تحرير اتصال، إعادة قفل mutex) حتى إذا حدث استثناء في المنتصف. هذا هو مدير السياق.

المشكلة بدون with

main.go

with تجعل try/finally ضمنياً وتُخفي الكود المتكرر. لكن كيف تعمل؟

بروتوكول مدير السياق — Context Manager Protocol

أي كائن ينفّذ طريقتين يمكن استخدامه مع with:

  • __enter__(self) — تُنفَّذ عند دخول كتلة with، تُرجع قيمة تُسنَد بـas
  • __exit__(self, exc_type, exc_val, exc_tb) — تُنفَّذ عند الخروج من الكتلة، سواء بنجاح أو بخطأ
main.go

معاملات __exit__ تُخبرك عن الاستثناء إن وُجد:

  • إذا لم يكن هناك استثناء: الثلاثة تكون None
  • إذا أرجعت True: الاستثناء يُلغى ولا يُنتشر
  • إذا أرجعت False أو لم تُرجع: الاستثناء يستمر

contextlib.contextmanager — الطريقة الأسهل

بدلاً من كتابة class كاملة، يمكنك استخدام @contextmanager مع yield:

main.go

الجزء قبل yield يعادل __enter__، والجزء بعده (في finally) يعادل __exit__. استخدام try/finally مع yield يضمن تنفيذ كود التنظيف حتى عند الاستثناءات.

مثال عملي — قفل mutex مزيّف

main.go

تغيير وضع السياق — Changing Context State

مدراء السياق قادرون على تغيير حالة مؤقتة ثم إعادتها. مثال: تغيير الدقة العشرية مؤقتاً:

main.go

استخدام with مع كائنات متعددة

يمكن استخدام كائنات متعددة في with واحدة:

main.go

متى تكتب مدير سياق خاص بك؟

كلما وجدت نمطاً متكرراً مثل:

  • افتح مورداً → استخدمه → أغلقه
  • احفظ حالة → غيّرها → أعِدها
  • ابدأ عملية → انهها (أو تراجع عن عواقبها)

هذا النمط يُرشّح لمدير سياق. الفائدة ليست فقط اختصار الكتابة، بل ضمان التنظيف حتى عند الأخطاء غير المتوقعة.

تحدي — Challenge