0Pricing
Python Academy · درس

بروتوكول __enter__ و__exit__

أنشئ مديري سياق باستخدام بروتوكول dunder

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

بروتوكول مدير السياق

أي كائن يعرّف __enter__ و__exit__ هو مدير سياق، ويمكن استخدامه مع with.

class Managed:
    def __enter__(self):
        print("entering")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("exiting")
        return False

with Managed() as m:
    print("inside")

القيمة المُرجعة من ‎__enter__‎

يُستدعى __enter__ عند بداية كتلة with. وتُربط القيمة التي يُرجعها بالمتغير الذي يأتي بعد as.

class Resource:
    def __enter__(self):
        self.value = 42
        return self  # bound to 'r'

    def __exit__(self, *args):
        self.value = None
        return False

with Resource() as r:
    print(r.value)  # 42

وسائط ‎__exit__‎

يستقبل __exit__(exc_type, exc_val, exc_tb) معلومات الاستثناء إذا وقع خطأ. وإذا لم يقع استثناء، تكون القيم الثلاث كلها None.

class Safe:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is ValueError:
            print(f"Suppressed ValueError: {exc_val}")
            return True   # suppress the exception
        return False      # re-raise anything else

with Safe():
    raise ValueError("oops")  # suppressed

إخفاء الاستثناءات

أرجع True من __exit__ لإخفاء الاستثناء. وأرجع False أو لا تُرجع شيئًا للسماح بانتقاله.

class Ignore:
    def __enter__(self): return self
    def __exit__(self, *args): return True  # swallow all exceptions

with Ignore():
    1 / 0

print("continues here")

مثال على اتصال بقاعدة بيانات

حالة استخدام كلاسيكية: الحصول على اتصال عند الدخول، ثم تثبيت التغييرات أو التراجع عنها وإغلاق الاتصال عند الخروج.

class DBConn:
    def __enter__(self):
        self.conn = connect_db()
        return self.conn

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            self.conn.rollback()
        else:
            self.conn.commit()
        self.conn.close()
        return False

مدير سياق لمؤقت

قِس الوقت المنقضي عبر تسجيل وقت البدء في __enter__ وحساب الفرق في __exit__.

import time

class Timer:
    def __enter__(self):
        self.start = time.perf_counter()
        return self

    def __exit__(self, *args):
        self.elapsed = time.perf_counter() - self.start
        print(f"Elapsed: {self.elapsed:.3f}s")
        return False

with Timer():
    sum(range(1_000_000))

تداخل مديري السياق

يمكن دمج عدة مديري سياق في سطر with واحد.

with open("in.txt") as src, open("out.txt", "w") as dst:
    dst.write(src.read())

مديرو السياق القابلون لإعادة الاستخدام مقابل المستخدمين مرة واحدة

مديرو السياق الذين يخصّص __enter__ لديهم موردًا جديدًا في كل مرة قابلون لإعادة الاستخدام. أما الذين يستنفدون حالة داخلية، مثل قفل لا يُمسك إلا مرة واحدة، فقد لا يكونون كذلك.

class Reusable:
    def __enter__(self):
        return []
    def __exit__(self, *a):
        return False

for _ in range(3):
    with Reusable() as lst:
        lst.append(1)
        print(lst)  # [1] each time

‎__aenter__‎ و‎__aexit__‎ ‏(غير متزامن)

بالنسبة إلى مديري السياق غير المتزامنين، عرّف الدالتين غير المتزامنتين __aenter__ و__aexit__، واستخدم async with.

class AsyncDB:
    async def __aenter__(self):
        self.conn = await connect()
        return self.conn

    async def __aexit__(self, *args):
        await self.conn.close()

# async with AsyncDB() as conn:
#     ...

تغليف كائنات الملفات

تنفذ كائنات الملفات في Python بروتوكول مدير السياق مسبقًا، لذا لا تستدعِ f.close() يدويًا أبدًا.

with open("data.txt", "r") as f:
    data = f.read()
# file is closed here automatically
print(f.closed)  # True

تنفيذ قفل

أقفال مؤشرات الترابط هي مديرو سياق: يستحوذ __enter__ على القفل، ويحرره __exit__.

import threading

lock = threading.Lock()

def update_shared():
    with lock:
        # critical section
        pass

تحقق سريع

ما الذي يجب أن تُعيده __exit__ لكبت استثناء؟

مراجعة

نفّذ __enter__ و__exit__ لإنشاء مديري سياق. أعد المورد من __enter__، وتولَّ التنظيف وكبت الاستثناءات في __exit__.

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

هل درس «بروتوكول __enter__ و__exit__» مجاني؟

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

ماذا ستتعلم في «بروتوكول __enter__ و__exit__»؟

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

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

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

كم من الوقت يستغرق درس «بروتوكول __enter__ و__exit__»؟

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

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

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

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

  1. عبارة with بالتفصيل
  2. بروتوكول __enter__ و__exit__
  3. contextlib: @contextmanager
  4. أنماط مديري السياق العملية
← العودة إلى Python Academy