2.24. مديرو السياق¶
تُشغّل عبارة with شيفرة الإعداد، ثم جسماً، ثم شيفرة التفكيك -- مع ضمان أن يُشغَّل التفكيك حتى عندما يفشل الجسم في منتصف الطريق. ويُسمى زوج التوابع الذي يوفّر الإعداد والتفكيك مدير سياق.
الصيغة هي:
with <expression> as <name>:
<body>
يعيد التعبير مدير سياق. يستدعي Python تابعه __enter__، ويربط النتيجة اختيارياً بـ <name>، ويشغّل الجسم، ثم يستدعي __exit__ -- سواء اكتمل الجسم بشكل طبيعي أو أطلق استثناءً.
يُشغَّل __exit__ في نهاية الكتلة مهما حدث داخلها.¶
2.24.1. استخدام مدير سياق¶
المثال النموذجي هو فتح ملف:
with open("data.txt") as f:
text = f.read()
# f is now closed, even if read() failed
تعيد open() كائن ملف هو بحدّ ذاته مدير سياق؛ يعيد __enter__ الملف، ويغلقه __exit__. تجعل كتلة with من "إغلاق الملف دائماً عند الانتهاء" السلوك الافتراضي بدلاً من أن يكون شيئاً على المستدعي أن يتذكره.
2.24.1.1. مديرو سياق متعددون¶
يمكن لعبارة with واحدة أن تدخل عدة مديري سياق دفعة واحدة، مفصولين بفواصل:
with open("input.txt") as src, open("output.txt", "w") as dst:
dst.write(src.read())
وهذا مكافئ لكتلتي with متداخلتين، لكن بشكل أكثر استواءً. يُدخَل المديرون من اليسار إلى اليمين ويُخرَج منهم بالترتيب العكسي؛ وإذا أطلق __enter__ على المدير الأيمن استثناءً، فإن __exit__ الخاص بالمدير الأيسر يُشغَّل مع ذلك.
2.24.2. كتابة مدير سياق¶
أي صنف يحوي التابعين __enter__ و __exit__ يعمل كمدير سياق:
class Section:
def __init__(self, label):
self.label = label
def __enter__(self):
print("---", self.label, "---")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("--- end", self.label, "---")
return False
with Section("setup"):
print("doing the work")
المخرجات:
--- setup ---
doing the work
--- end setup ---
يتلقى __exit__ ثلاث وسائط تصف الاستثناء الذي أنهى الكتلة، أو ثلاث قيم None إذا اكتملت الكتلة بشكل طبيعي. وإعادة False (أو None) تسمح لأي استثناء بالانتشار بعد التفكيك؛ بينما إعادة True تبتلعه.
استخدم مديري السياق لأي مورد له دورة حياة "فتح / إغلاق" أو "اكتساب / تحرير" -- وليس الملفات فقط. يُبقي هذا النمط التنظيف مقروناً بالإعداد عند النقطة التي يُقدَّمان فيها معاً، بحيث لا يمكن لإغلاقٍ منسيٍّ في منتصف دالة طويلة أن يُسرّب المورد.