خانه / آموزش‌ها / ماژول contextlib در پایتون

ماژول contextlib در پایتون

🐍 HomeOfPython
|
📅 1404/10/24

سطح مقدماتی (Beginner Level)

ماژول contextlib در کتابخانه استاندارد پایتون (Standard Library) ابزارهایی را فراهم می‌کند که کار با دستور with و Context Managerها را بسیار ساده‌تر می‌کند. اگر پیش از این برای ساخت یک Context Manager مجبور بودید یک کلاس کامل با متدهای __enter__ و __exit__ بنویسید، این ماژول به شما اجازه می‌دهد کدهای تمیزتر و کوتاه‌تری بنویسید.

۱. نادیده گرفتن خطاها با suppress

یکی از رایج‌ترین کاربردهای contextlib، متد suppress است. این متد جایگزین بلوک‌های try-except-pass می‌شود و به شما اجازه می‌دهد خطاهای مشخصی را به‌صورت ایمن نادیده بگیرید.

مثال اول: حذف فایل بدون بررسی وجود آن

به جای اینکه چک کنید فایل وجود دارد یا نه، یا از try-except استفاده کنید، می‌توانید خطای FileNotFoundError را سرکوب (Suppress) کنید.

Python

مثال دوم: دریافت مقدار از دیکشنری (شبیه سازی)

اگر بخواهیم عملیاتی انجام دهیم که ممکن است KeyError یا IndexError بدهد و برایمان مهم نباشد:

Python

۲. مدیریت خروجی‌ها با redirect_stdout

گاهی نیاز دارید خروجی printهای یک تابع یا کد را به جای کنسول، به یک فایل یا یک متغیر رشته‌ای هدایت کنید. redirect_stdout این کار را به سادگی انجام می‌دهد.

مثال اول: ذخیره پرینت در یک فایل

Python

مثال دوم: ساکت کردن کد (Silencing)

اگر می‌خواهید خروجی یک کد را کلاً حذف کنید (مثلاً یک کتابخانه که پرینت‌های مزاحم دارد):

python
import io
from contextlib import redirect_stdout

def noisy_library():
    print("SYSTEM WARNING: ...")

# هدایت خروجی به ناکجا (یک بافر خالی)
with redirect_stdout(io.StringIO()):
    noisy_library()
# هیچ چیزی در کنسول چاپ نمی‌شود

سطح پیشرفته (Professional Level)

در سطح حرفه‌ای، contextlib قدرت واقعی خود را با دکوراتورها نشان می‌دهد. شما می‌توانید با استفاده از Generatorها، Context Manager بسازید و نیازی به تعریف کلاس ندارید.

۱. دکوراتور contextmanager@

این دکوراتور جادویی است. به جای نوشتن کلاس با __enter__ و __exit__، شما یک تابع می‌نویسید که یک بار yield می‌کند.

  • کدِ قبل از yield: معادل __enter__
  • کدِ بعد از yield: معادل __exit__

مثال اول: ساخت تایمر ساده

Python

مثال دوم: مدیریت کانکشن (Mock Database)

استفاده از try-finally داخل ژنراتور تضمین می‌کند که حتی اگر در بلاک with خطا رخ دهد، کدِ بعد از yield (بستن منابع) اجرا شود.

Python

۲. کلاس ContextDecorator

اگر بخواهید Context Manager شما هم به صورت with و هم به صورت دکوراتور (@) قابل استفاده باشد، می‌توانید از ContextDecorator ارث‌بری کنید. با این حال، contextmanager@ که در بالا گفتیم خودش این قابلیت را دارد!

مثال: استفاده به عنوان دکوراتور

همان تایمری که در بالا ساختیم را می‌توانیم روی تابع بگذاریم:

Python

۳. مدیریت داینامیک با ExitStack

این یکی از پیشرفته‌ترین ابزارهای contextlib است. زمانی که شما نمی‌دانید دقیقاً چند فایل یا منبع را باید باز کنید (مثلاً لیستی از فایل‌ها دارید)، نمی‌توانید از چندین with تو در تو استفاده کنید. ExitStack به شما اجازه می‌دهد Context Managerها را به صورت پویا و در یک پشته (Stack) مدیریت کنید.

مثال فنی: باز کردن تعداد نامشخصی فایل

فرض کنید یک لیست از نام فایل‌ها داریم و می‌خواهیم همه را همزمان باز نگه داریم و در آخر همه را ببندیم.

Python

۴. متد closing

برای اشیایی که متد close() دارند اما از پروتکل Context Manager (__enter__) پشتیبانی نمی‌کنند (معمولاً در کدهای قدیمی یا برخی کتابخانه‌های شبکه)، می‌توان از closing استفاده کرد تا مطمئن شویم close() صدا زده می‌شود.

python
from contextlib import closing
from urllib.request import urlopen

# urlopen در پایتون ۳ خود Context Manager است، اما برای مثال:
with closing(urlopen("https://www.python.org")) as page:
    for line in page:
        print(line)
        break
# page.close() is called automatically here