دروس الوحدة (3/4)
مدير السياق: مع و __أدخل__/__خروج__
مدير السياق هو كائن تستخدمه مع with. يضمن ذلك
تحدث دائمًا عمليات إعداد/تنظيف معينة، حتى عند حدوث أخطاء.
المثال القانوني: فتح وإغلاق ملف.
النمط with
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 في كل مرة.
أكثر من واحد في وقت واحد
with open("a.txt") as f, open("b.txt") as g:
dati_a = f.read()
dati_b = g.read()كتابة مدير السياق الخاص بك (الفصل)
تحتاج إلى تحديد طريقتين أقل دقة: __enter__ و__exit__.
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 كتابة مدير السياق كملف
وظيفة المولد:
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 التنظيف حتى عند حدوث أخطاء.
قمع: تجاهل استثناء
from contextlib import suppress
with suppress(FileNotFoundError):
open("forse-non-esiste.txt").read()
# se il file non c'è, nessun errore propagaالمأزق: with فقط للكائنات التي تدعمه
x = 42
with x: # AttributeError: __enter__
...كتابة مديري السياق باستخدامcontextmanager
تقوم وحدة contextlib الخاصة بالمكتبة القياسية بتصدير مصمم ديكور مناسب للغاية يسمى @contextmanager لإنشاء مديري سياق باستخدام وظائف المولد، بدلاً من كتابة فئات مطولة تنفذ أساليب __enter__ و__exit__. ما عليك سوى كتابة دالة منشئة تستخدم yield واحدًا:
from contextlib import contextmanager
@contextmanager
def manage_resource():
# __enter__ code
yield resource
# __exit__ codeجربه بنفسك
استخدم contextlib.suppress لمحاولة int('non-numero') متجاهلاً ValueError. بعد الكتلة قم بتعيين `ok = True`. تقييم "حسنا".
إظهار التلميح
قمع (ValueError) يبتلع ValueError فقط.
الحل متاح بعد 3 من المحاولات
تمرين المراجعة
اكتب مدير السياق `collect` باستخدام @contextmanager الذي ينتج قائمة فارغة، وعند الخروج، يحولها إلى صف (اطبعه). استخدمه لإلحاق 1، 2، 3 بالقائمة الموجودة داخل الكتلة. في النهاية، قم بتقييم `len(collection)` حيث `collection` هي القائمة الناتجة.
إظهار التلميح
عناصر العائد لكشف القائمة داخل الكتلة.
الحل متاح بعد 3 من المحاولات
التحدي الإضافي
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 من المحاولات