Context Manager در پایتون چیست؟
آموزش دستور with، متدهای
__enter__ و __exit__
و ساخت Context Manager در پایتون
Context Manager چیست؟
در برنامهنویسی گاهی لازم است قبل از انجام یک کار، یک منبع را آماده کنیم و بعد از پایان کار آن را آزاد کنیم.
برای مثال هنگام کار با فایل، معمولاً باید فایل را باز کنیم، اطلاعات موردنظر را بخوانیم یا بنویسیم و در نهایت فایل را ببندیم.
پایتون برای مدیریت ساده و مطمئن چنین منابعی قابلیتی به نام Context Manager در اختیار ما قرار میدهد.
معروفترین شکل استفاده از Context Manager در پایتون،
دستور with است.
دستور with در پایتون چیست؟
دستور with کمک میکند یک منبع را برای مدت مشخصی
در اختیار داشته باشیم و پس از پایان کار، عملیات لازم برای
آزادسازی آن منبع بهصورت خودکار انجام شود.
یک نمونه بسیار ساده برای کار با فایل:
with open("data.txt", "r") as file:
content = file.read()
print(content)
در این مثال فایل باز میشود و داخل بلوک with
مورد استفاده قرار میگیرد.
بعد از خارج شدن از بلوک with،
فایل بهصورت خودکار بسته میشود.
چرا به جای روش معمول از with استفاده کنیم؟
میتوان فایل را بدون with نیز باز کرد:
file = open("data.txt", "r")
content = file.read()
file.close()
این روش در مثال ساده بالا کار میکند، اما اگر هنگام اجرای
عملیات روی فایل خطایی رخ دهد، ممکن است دستور
close() اجرا نشود.
استفاده از with باعث میشود مدیریت منابع
قابل اعتمادتر و کد خواناتر باشد.
with و مدیریت خطا
یکی از مزایای مهم Context Manager این است که حتی اگر
داخل بلوک with خطایی رخ دهد، عملیات خروج
از Context انجام میشود.
with open("data.txt", "r") as file:
data = file.read()
print(data)
# ممکن است اینجا خطایی رخ دهد
پس از پایان Context، فایل بسته خواهد شد.
به همین دلیل with برای مدیریت منابع بسیار مفید است.
Context Manager چگونه کار میکند؟
یک Context Manager معمولاً دو متد مهم دارد:
__enter__()__exit__()
متد __enter__ هنگام ورود به Context اجرا میشود.
متد __exit__ هنگام خروج از Context اجرا میشود.
متد __enter__ چیست؟
متد __enter__ زمانی اجرا میشود که برنامه
وارد بلوک with میشود.
class MyContext:
def __enter__(self):
print("ورود به Context")
return self
مقداری که از __enter__ برگردانده میشود،
میتواند با as دریافت شود.
متد __exit__ چیست؟
متد __exit__ هنگام خروج از بلوک
with اجرا میشود.
class MyContext:
def __exit__(self, exc_type, exc_value, traceback):
print("خروج از Context")
پارامترهای این متد اطلاعات مربوط به خطای احتمالی را نیز در اختیار Context Manager قرار میدهند.
ساخت یک Context Manager ساده
حالا یک Context Manager ساده میسازیم:
class MyContext:
def __enter__(self):
print("شروع کار")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("پایان کار")
with MyContext() as context:
print("داخل Context هستیم")
خروجی تقریباً به شکل زیر خواهد بود:
شروع کار
داخل Context هستیم
پایان کار
استفاده از as در Context Manager
میتوان نتیجه متد __enter__ را با
as دریافت کرد.
class Database:
def __enter__(self):
print("اتصال به دیتابیس")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("بستن اتصال")
with Database() as db:
print("در حال استفاده از دیتابیس")
در این مثال متغیر db همان مقداری است که
متد __enter__ برگردانده است.
کتابخانه contextlib چیست؟
پایتون کتابخانهای به نام contextlib دارد
که ساخت Context Managerها را سادهتر میکند.
یکی از ابزارهای مهم این کتابخانه،
دکوراتور @contextmanager است.
ساخت Context Manager با @contextmanager
با استفاده از @contextmanager میتوان
بدون نوشتن مستقیم __enter__ و
__exit__ یک Context Manager ساخت.
from contextlib import contextmanager
@contextmanager
def my_context():
print("شروع Context")
yield
print("پایان Context")
with my_context():
print("داخل Context")
خروجی:
شروع Context
داخل Context
پایان Context
دستور yield در اینجا نقطهای را مشخص میکند
که کنترل وارد بدنه with میشود.
استفاده از try و finally در Context Manager
برای اینکه عملیات پایانی حتی هنگام رخ دادن خطا انجام شود،
معمولاً از try و finally استفاده میکنیم.
from contextlib import contextmanager
@contextmanager
def my_context():
print("شروع کار")
try:
yield
finally:
print("پاکسازی منابع")
with my_context():
print("انجام عملیات")
بخش finally برای عملیات Cleanup بسیار مهم است.
مثال کاربردی: اندازهگیری زمان اجرای برنامه
میتوان از Context Manager برای اندازهگیری زمان اجرای یک بخش از برنامه استفاده کرد.
from contextlib import contextmanager
import time
@contextmanager
def timer():
start = time.time()
try:
yield
finally:
end = time.time()
print("زمان اجرا:", end - start)
with timer():
time.sleep(2)
این Context Manager قبل از اجرای کد زمان شروع را ذخیره میکند و پس از پایان کار مدت زمان اجرای کد را نمایش میدهد.
Context Manager و فایلها
یکی از رایجترین نمونههای Context Manager در پایتون،
تابع open() است.
with open("python.txt", "w", encoding="utf-8") as file:
file.write("PythonAI")
پس از پایان بلوک with، فایل بسته میشود.
این روش باعث میشود لازم نباشد هر بار بهصورت دستی
file.close() را بنویسیم.
تفاوت Context Manager و Decorator
Decorator و Context Manager هر دو برای مدیریت و تغییر رفتار برنامه کاربرد دارند، اما هدف یکسانی ندارند.
- Decorator: رفتار یک تابع یا کلاس را تغییر یا گسترش میدهد.
- Context Manager: ورود و خروج از یک محدوده مشخص از کد یا مدیریت منابع را کنترل میکند.
در درس قبلی با Decoratorها آشنا شدیم و اکنون Context Manager یکی دیگر از ابزارهای مهم پایتون است.
کاربردهای Context Manager
Context Managerها در پروژههای واقعی کاربردهای زیادی دارند.
- باز کردن و بستن فایلها
- اتصال و قطع اتصال دیتابیس
- مدیریت Lock در برنامههای چندنخی
- مدیریت منابع سیستم
- مدیریت تراکنشهای دیتابیس
- اندازهگیری زمان اجرای کد
- مدیریت Session و Connection
- پاکسازی منابع پس از پایان عملیات
اشتباهات رایج در استفاده از Context Manager
۱. فراموش کردن finally
هنگام ساخت Context Manager با @contextmanager
بهتر است عملیات Cleanup را در بخش finally
قرار دهیم.
۲. استفاده نادرست از yield
در Context Managerهای ساختهشده با
@contextmanager باید ساختار تابع بهدرستی
طراحی شود تا ورود و خروج Context مشخص باشد.
۳. پیچیده کردن بیش از حد Context Manager
اگر یک Context Manager ساده را میتوان با چند خط کد واضح نوشت، نیازی نیست آن را بیش از حد پیچیده کنیم.
جمعبندی Context Manager در پایتون
Context Manager یکی از قابلیتهای مهم پایتون برای مدیریت منابع و کنترل ورود و خروج از یک محدوده مشخص است.
مهمترین ابزار برای استفاده از آن، دستور with است.
همچنین با متدهای __enter__ و
__exit__ میتوان Context Manager اختصاصی ساخت.
کتابخانه contextlib نیز ساخت Context Managerها
را سادهتر میکند و @contextmanager یکی از
کاربردیترین ابزارهای آن است.
یادگیری Context Manager برای پروژههای واقعی پایتون، مخصوصاً کار با فایلها، دیتابیس و منابع مختلف، بسیار مفید است.
تمرینهای Context Manager
-
یک Context Manager بسازید که هنگام ورود عبارت
شروع برنامهو هنگام خروج عبارتپایان برنامهرا نمایش دهد. -
یک Context Manager با
@contextmanagerبنویسید که زمان اجرای یک قطعه کد را اندازهگیری کند. - یک Context Manager برای مدیریت یک فایل متنی ایجاد کنید.
-
بررسی کنید اگر داخل بلوک
withخطایی رخ دهد، متد__exit__چگونه اجرا میشود.
سوالات متداول
Context Manager در پایتون چیست؟
Context Manager ابزاری برای مدیریت ورود و خروج از یک محدوده مشخص و معمولاً مدیریت منابعی مانند فایل، اتصال دیتابیس یا Lock است.
دستور with چه کاری انجام میدهد؟
دستور with ورود و خروج از یک Context را
مدیریت میکند و امکان انجام عملیات Cleanup را فراهم میسازد.
__enter__ و __exit__ چه هستند؟
این دو متد برای ساخت Context Managerهای مبتنی بر کلاس
استفاده میشوند. __enter__ هنگام ورود و
__exit__ هنگام خروج اجرا میشود.
@contextmanager چیست؟
@contextmanager یک دکوراتور از کتابخانه
contextlib است که ساخت Context Manager را
با استفاده از یک تابع و yield ساده میکند.
آیا with فقط برای فایلها استفاده میشود؟
خیر. Context Manager میتواند برای فایلها، دیتابیس، Lock، Session، Connection و بسیاری از منابع دیگر استفاده شود.