الانتقال إلى المحتوى الرئيسي
الوحدة 9 · الدرس 3 من 435/36 في الدورة~12 min
دروس الوحدة (3/4)

مدير السياق: مع و __أدخل__/__خروج__

مدير السياق هو كائن تستخدمه مع with. يضمن ذلك تحدث دائمًا عمليات إعداد/تنظيف معينة، حتى عند حدوث أخطاء. المثال القانوني: فتح وإغلاق ملف.

النمط with

Python
with open("note.txt", "w") as f:
    f.write("ciao")
# qui f è già chiuso, anche se write() ha sollevato un'eccezione

باللغة الإنجليزية البسيطة: "مع المورد X مفتوح كـ f، قم بذلك. عند الانتهاء (مهما حدث)، أغلق X." بدون with سيكون عليك الكتابة try/finally في كل مرة.

أكثر من واحد في وقت واحد

Python
with open("a.txt") as f, open("b.txt") as g:
    dati_a = f.read()
    dati_b = g.read()

كتابة مدير السياق الخاص بك (الفصل)

تحتاج إلى تحديد طريقتين أقل دقة: __enter__ و__exit__.

Python
class Timer:
    def __enter__(self):
        import time
        self.t0 = time.perf_counter()
        return self  # è l'oggetto che finisce dopo "as"
    def __exit__(self, exc_type, exc_value, traceback):
        import time
        self.elapsed = time.perf_counter() - self.t0
        # ritornare True ingoia l'eccezione; di solito non lo vuoi
        return False

with Timer() as t:
    sum(range(10**6))
t.elapsed  # quanto è durato
  • يتم استدعاء __enter__(self) عند دخول الكتلة؛ القيمة التي تم إرجاعها هي ما تحصل عليه بعد as.
  • يتم استدعاء __exit__(self, exc_type, exc_value, tb) عند الخروج (دائمًا). إذا أعادت True، فسيتم منع أي استثناءات.

الاختصار: @contextmanager

يتيح لك contextlib.contextmanager كتابة مدير السياق كملف وظيفة المولد:

Python
from contextlib import contextmanager

@contextmanager
def timer():
    import time
    t0 = time.perf_counter()
    try:
        yield  # qui sta il blocco "with"
    finally:
        elapsed = time.perf_counter() - t0
        print(f"durata: {elapsed:.4f}s")

with timer():
    sum(range(10**6))

الكود قبل yield هو __enter__، الكود بعد هو __exit__. يضمن try/finally التنظيف حتى عند حدوث أخطاء.

قمع: تجاهل استثناء

Python
from contextlib import suppress

with suppress(FileNotFoundError):
    open("forse-non-esiste.txt").read()
# se il file non c'è, nessun errore propaga

المأزق: with فقط للكائنات التي تدعمه

Python
x = 42
with x:  # AttributeError: __enter__
    ...

كتابة مديري السياق باستخدامcontextmanager

تقوم وحدة contextlib الخاصة بالمكتبة القياسية بتصدير مصمم ديكور مناسب للغاية يسمى @contextmanager لإنشاء مديري سياق باستخدام وظائف المولد، بدلاً من كتابة فئات مطولة تنفذ أساليب __enter__ و__exit__. ما عليك سوى كتابة دالة منشئة تستخدم yield واحدًا:

Python
from contextlib import contextmanager

@contextmanager
def manage_resource():
    # __enter__ code
    yield resource
    # __exit__ code

جربه بنفسك

تمرين#python.m9.l3.e1
المحاولات: 0جارٍ التحميل…

استخدم contextlib.suppress لمحاولة int('non-numero') متجاهلاً ValueError. بعد الكتلة قم بتعيين `ok = True`. تقييم "حسنا".

جارٍ تحميل المحرر…
إظهار التلميح

قمع (ValueError) يبتلع ValueError فقط.

الحل متاح بعد 3 من المحاولات

تمرين المراجعة

تمرين#python.m9.l3.e2
المحاولات: 0جارٍ التحميل…

اكتب مدير السياق `collect` باستخدام @contextmanager الذي ينتج قائمة فارغة، وعند الخروج، يحولها إلى صف (اطبعه). استخدمه لإلحاق 1، 2، 3 بالقائمة الموجودة داخل الكتلة. في النهاية، قم بتقييم `len(collection)` حيث `collection` هي القائمة الناتجة.

جارٍ تحميل المحرر…
إظهار التلميح

عناصر العائد لكشف القائمة داخل الكتلة.

الحل متاح بعد 3 من المحاولات

التحدي الإضافي

تمرين#python.m9.l3.e3
المحاولات: 0جارٍ التحميل…

Write a custom context manager using the `@contextmanager` decorator from `contextlib`. The context manager must be named `mock_session`. Upon entry, it must append `'start'` to a global list `log_list = []`, yield control using `yield`, and upon exit append `'stop'`. Finally, evaluate `log_list` after using the context manager with `with mock_session():`.

جارٍ تحميل المحرر…
إظهار التلميح

استخدم العائد داخل mock_session لتعليق التنفيذ قبل إلحاق "الإيقاف".

الحل متاح بعد 3 من المحاولات