🐍 آموزش جامع Python — پست ۱۲۵
مدیریت چند Context Manager با
گاهی لازم است چند منبع را همزمان مدیریت کنیم.
مثلاً چند فایل، اتصال یا Resource مختلف.
برای این کار
🔹 مشکل چیست؟
میتوانیم چند
اما اگر تعداد Context Managerها پویا باشد، این روش مناسب نیست.
🔹
با
در پایان بلوک
🔹
برای وارد کردن یک Resource به
استفاده میکنیم.
مثلاً:
هر بار که
مقدار برگشتی
پس:
و هنگام خروج:
یعنی Resourceها به ترتیب ورود وارد میشوند، اما به ترتیب معکوس خارج میشوند.
🔹 چرا
فرض کنیم تعداد فایلها مشخص نیست:
میتوانیم همه را با یک حلقه باز کنیم:
اینجا تعداد فایلها میتواند تغییر کند، بدون اینکه تعداد
🔹 ترتیب خروج
اگر:
باشد، هنگام خروج:
این رفتار شبیه ساختار Stack است:
🔹 اضافه کردن Cleanup
خروجی:
تابع
⚠️ نکته مهم
تعداد Context Managerها از قبل مشخص نیست.
منابع بهصورت پویا ایجاد میشوند.
چند Resource باید با هم مدیریت شوند.
Cleanup باید حتی هنگام رخ دادن Exception انجام شود.
🧠 خلاصه
و ترتیب خروج:
🎯 تمرین
کد زیر را کامل کن تا سه Resource را با
خروجی مورد انتظار:
پست ۱۲۵ از دوره جامع Python 🐍
مدیریت چند Context Manager با
ExitStackگاهی لازم است چند منبع را همزمان مدیریت کنیم.
مثلاً چند فایل، اتصال یا Resource مختلف.
برای این کار
contextlib ابزاری به نام ExitStack دارد.🔹 مشکل چیست؟
میتوانیم چند
with را داخل هم بنویسیم:with open("file1.txt") as file1:
with open("file2.txt") as file2:
print("Working...")اما اگر تعداد Context Managerها پویا باشد، این روش مناسب نیست.
🔹
ExitStackبا
ExitStack میتوانیم Context Managerها را بهصورت پویا مدیریت کنیم:from contextlib import ExitStack
with ExitStack() as stack:
file1 = stack.enter_context(open("file1.txt"))
file2 = stack.enter_context(open("file2.txt"))
print("Working...")
در پایان بلوک
with، منابع مدیریتشده توسط stack بهصورت خودکار خارج میشوند.🔹
enter_context() چگونه کار میکند؟برای وارد کردن یک Resource به
ExitStack از:stack.enter_context(resource)
استفاده میکنیم.
مثلاً:
with ExitStack() as stack:
resource_a = stack.enter_context(Resource("A"))
resource_b = stack.enter_context(Resource("B"))
resource_c = stack.enter_context(Resource("C"))
print("Working...")
هر بار که
enter_context() اجرا میشود:__enter__() همان Resource اجرا میشود.مقدار برگشتی
__enter__() برگردانده میشود.__exit__() برای زمان خروج توسط ExitStack ثبت میشود.پس:
Resource("A")
↓
A.__enter__()
Resource("B")
↓
B.__enter__()
Resource("C")
↓
C.__enter__()و هنگام خروج:
C.__exit__()
↓
B.__exit__()
↓
A.__exit__()
یعنی Resourceها به ترتیب ورود وارد میشوند، اما به ترتیب معکوس خارج میشوند.
🔹 چرا
ExitStack مفید است؟فرض کنیم تعداد فایلها مشخص نیست:
files = ["a.txt", "b.txt", "c.txt"]
میتوانیم همه را با یک حلقه باز کنیم:
from contextlib import ExitStack
files = ["a.txt", "b.txt", "c.txt"]
with ExitStack() as stack:
opened_files = []
for filename in files:
file = stack.enter_context(open(filename))
opened_files.append(file)
print(len(opened_files))
اینجا تعداد فایلها میتواند تغییر کند، بدون اینکه تعداد
withها را از قبل مشخص کنیم.🔹 ترتیب خروج
ExitStack Context Managerها را به ترتیب معکوس ورود خارج میکند.اگر:
A → ورود
B → ورود
C → ورود
باشد، هنگام خروج:
C → خروج
B → خروج
A → خروج
این رفتار شبیه ساختار Stack است:
Last In → First Out
🔹 اضافه کردن Cleanup
ExitStack حتی میتواند یک تابع cleanup را هم ثبت کند:from contextlib import ExitStack
def cleanup():
print("Cleanup done")
with ExitStack() as stack:
stack.callback(cleanup)
print("Working...")
خروجی:
Working...
Cleanup done
تابع
cleanup هنگام خروج از with اجرا میشود.⚠️ نکته مهم
ExitStack زمانی بسیار مفید است که:تعداد Context Managerها از قبل مشخص نیست.
منابع بهصورت پویا ایجاد میشوند.
چند Resource باید با هم مدیریت شوند.
Cleanup باید حتی هنگام رخ دادن Exception انجام شود.
🧠 خلاصه
ExitStack
↓
مدیریت چند Context Manager
↓
enter_context()
↓
__enter__()
↓
مدیریت Resource
↓
__exit__()
و ترتیب خروج:
A → B → C
↓
C → B → A
🎯 تمرین
کد زیر را کامل کن تا سه Resource را با
ExitStack مدیریت کند:from contextlib import ExitStack
class Resource:
def __init__(self, name):
self.name = name
def __enter__(self):
print(f"{self.name} started")
return self
def __exit__(self, exc_type, exc_value, traceback):
print(f"{self.name} closed")
with ExitStack() as stack:
# سه Resource با نامهای A ،B و C را وارد Stack کن
# سپس عبارت زیر را چاپ کن:
print("Working...")
خروجی مورد انتظار:
A started
B started
C started
Working...
C closed
B closed
A closed
پست ۱۲۵ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۱۲۶
مدیریت موقت Context Manager با
گاهی تعداد Resourceها مشخص نیست یا یک Resource فقط در شرایط خاصی لازم است.
🔹 ورود شرطی Resource
اگر
🔹 اضافه کردن چند Resource
Resourceها هنگام خروج، برعکس ترتیب ورود cleanup میشوند:
همچنین میتوانیم تعداد متغیری Resource را با حلقه مدیریت کنیم:
🔹 اگر هنگام ورود Resource خطا رخ دهد؟
ممکن است
حالا:
خروجی:
چون
اما
🔹 مدیریت خطا با
میتوانیم خطای ورود را مدیریت کنیم:
خروجی:
اینجا:
⚠️ نکته مهم
اگر نخواهیم خطا را متوقف کنیم، آن را در
اگر بخواهیم خطا دوباره به بیرون منتقل شود:
🧠 خلاصه
مزیت
🎯 تمرین
کد را کامل کن:
خروجی مورد انتظار:
پست ۱۲۶ از دوره جامع Python 🐍
مدیریت موقت Context Manager با
ExitStackگاهی تعداد Resourceها مشخص نیست یا یک Resource فقط در شرایط خاصی لازم است.
ExitStack اجازه میدهد Resourceها را بهصورت پویا و شرطی وارد مدیریت کنیم.🔹 ورود شرطی Resource
from contextlib import ExitStack
use_cache = True
with ExitStack() as stack:
if use_cache:
cache = stack.enter_context(Resource("Cache"))
print("Application running")
اگر
use_cache برابر False باشد، Resource اصلاً وارد Stack نمیشود.🔹 اضافه کردن چند Resource
with ExitStack() as stack:
if condition_1:
resource_a = stack.enter_context(Resource("A"))
if condition_2:
resource_b = stack.enter_context(Resource("B"))
print("Working...")
Resourceها هنگام خروج، برعکس ترتیب ورود cleanup میشوند:
A → B → C
↓
C → B → A
همچنین میتوانیم تعداد متغیری Resource را با حلقه مدیریت کنیم:
resources = ["A", "B", "C"]
with ExitStack() as stack:
for name in resources:
stack.enter_context(Resource(name))
print("All resources are active")
🔹 اگر هنگام ورود Resource خطا رخ دهد؟
ممکن است
__enter__() یک Resource خطا ایجاد کند:class Resource:
def __init__(self, name):
self.name = name
def __enter__(self):
print(f"{self.name} started")
if self.name == "D":
raise RuntimeError("D failed")
return self
def __exit__(self, exc_type, exc_value, traceback):
print(f"{self.name} closed")
حالا:
with ExitStack() as stack:
a = stack.enter_context(Resource("A"))
d = stack.enter_context(Resource("D"))
print("Working...")
خروجی:
A started
D started
RuntimeError: D failed
A closed
چون
A قبلاً با موفقیت وارد Stack شده، در پایان cleanup میشود.اما
D به دلیل خطا در __enter__() وارد Stack نشده است.🔹 مدیریت خطا با
try/exceptمیتوانیم خطای ورود را مدیریت کنیم:
with ExitStack() as stack:
try:
a = stack.enter_context(Resource("A"))
d = stack.enter_context(Resource("D"))
except RuntimeError as error:
print("Failed to enter resource:", error)
print("Working...")
خروجی:
A started
D started
Failed to enter resource: D failed
Working...
A closed
اینجا:
try/except → مدیریت خطا
ExitStack → مدیریت Resourceها
A همچنان توسط ExitStack cleanup میشود.⚠️ نکته مهم
اگر نخواهیم خطا را متوقف کنیم، آن را در
except مدیریت میکنیم.اگر بخواهیم خطا دوباره به بیرون منتقل شود:
except RuntimeError as error:
print(error)
raise
🧠 خلاصه
enter_context()
↓
__enter__()
↓
موفق → ثبت __exit__
خطا → try/except
↓
Cleanup Resourceهای قبلی
مزیت
ExitStack:مدیریت پویا، شرطی و امن چند Resource، حتی زمانی که هنگام ورود یکی از آنها خطا رخ دهد.
🎯 تمرین
کد را کامل کن:
from contextlib import ExitStack
with ExitStack() as stack:
try:
# Resource A را وارد کن
# Resource D را وارد کن
pass
except RuntimeError as error:
print("Failed to enter resource:", error)
print("Working...")
خروجی مورد انتظار:
A started
D started
Failed to enter resource: D failed
Working...
A closed
پست ۱۲۶ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۲۷
ساخت Context Manager با
تا اینجا Context Manager را با کلاس و متدهای
اما Python روش سادهتری هم دارد:
با
🔹 ساخت یک Context Manager ساده
حالا میتوانیم از آن با
خروجی:
🔹
در Context Manager ساختهشده با
کد قبل از
کد بعد از
یعنی:
🔹 استفاده از
میتوانیم از
حالا:
خروجی:
مقداری که
⚠️ نکته مهم
ساختار کلی:
بخش
🎯 تمرین
یک Context Manager به نام
قبل از
داخل
بعد از
پست ۱۲۷ از دوره جامع Python 🐍
ساخت Context Manager با
@contextmanagerتا اینجا Context Manager را با کلاس و متدهای
__enter__() و __exit__() ساختیم.اما Python روش سادهتری هم دارد:
from contextlib import contextmanager
با
@contextmanager میتوانیم یک تابع را به Context Manager تبدیل کنیم.🔹 ساخت یک Context Manager ساده
from contextlib import contextmanager
@contextmanager
def my_context():
print("Start")
yield
print("End")
حالا میتوانیم از آن با
with استفاده کنیم:with my_context():
print("Working...")
خروجی:
Start
Working...
End
🔹
yield چه نقشی دارد؟در Context Manager ساختهشده با
@contextmanager:@contextmanager
def my_context():
# قبل از with
yield
# بعد از with
کد قبل از
yield هنگام ورود اجرا میشود.کد بعد از
yield هنگام خروج اجرا میشود.یعنی:
__enter__
↓
قبل از yield
↓
کد داخل with
↓
بعد از yield
↓
__exit__
🔹 استفاده از
asمیتوانیم از
yield یک مقدار برگردانیم:from contextlib import contextmanager
@contextmanager
def resource():
print("Opening")
data = "Python"
yield data
print("Closing")
حالا:
with resource() as value:
print(value)
خروجی:
Opening
Python
Closing
مقداری که
yield میکند، داخل متغیر value قرار میگیرد.⚠️ نکته مهم
@contextmanager از ما میخواهد تابع شامل yield باشد.ساختار کلی:
@contextmanager
def my_context():
# setup
yield value
# cleanup
بخش
setup قبل از yield و بخش cleanup بعد از آن قرار میگیرد.🎯 تمرین
یک Context Manager به نام
database_connection بساز که:قبل از
yield چاپ کند:Connecting...
داخل
with این پیام چاپ شود:Query running...
بعد از
yield چاپ کند:Connection closed.
پست ۱۲۷ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۲۸
مدیریت خطا در
در پست قبل یاد گرفتیم با
حالا باید ببینیم اگر داخل
🔹 استفاده از
میتوانیم
حالا:
خروجی:
خطا در محل
🔹 اگر خطا را مدیریت نکنیم
مثلاً:
اگر داخل
⚠️
در Context Managerها معمولاً cleanup را در
🧠 خلاصه
🎯 تمرین
کد را کامل کن تا خطای
پست ۱۲۸ از دوره جامع Python 🐍
مدیریت خطا در
@contextmanagerدر پست قبل یاد گرفتیم با
@contextmanager یک Context Manager بسازیم.حالا باید ببینیم اگر داخل
with خطایی رخ دهد، چطور آن را مدیریت کنیم.🔹 استفاده از
try/exceptمیتوانیم
yield را داخل try قرار دهیم:from contextlib import contextmanager
@contextmanager
def my_context():
print("Start")
try:
yield
except ValueError:
print("Value error handled")
print("End")
حالا:
with my_context():
print("Working...")
raise ValueError("Invalid value")
خروجی:
Start
Working...
Value error handled
End
خطا در محل
yield به Context Manager برمیگردد و except میتواند آن را مدیریت کند.🔹 اگر خطا را مدیریت نکنیم
مثلاً:
@contextmanager
def my_context():
print("Start")
try:
yield
finally:
print("Cleanup")
اگر داخل
with خطا رخ دهد:with my_context():
raise ValueError("Something went wrong")
finally اجرا میشود، اما خطا همچنان به بیرون منتقل میشود.Start
Cleanup
ValueError
⚠️
except و finallyexcept → برای مدیریت خطا
finally → برای cleanup که باید در هر حالت اجرا شود
در Context Managerها معمولاً cleanup را در
finally قرار میدهیم.🧠 خلاصه
@contextmanager
def my_context():
try:
# setup
yield
except ValueError:
# handle error
pass
finally:
# cleanup
pass
🎯 تمرین
کد را کامل کن تا خطای
ValueError مدیریت شود:from contextlib import contextmanager
@contextmanager
def database():
print("Connecting...")
try:
yield
except ValueError:
print("Invalid query")
finally:
print("Connection closed")
with database():
print("Query running...")
raise ValueError("Bad query")
پست ۱۲۸ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۲۹
Context Manager با مدیریت چند Resource
گاهی یک Context Manager خودش باید چند Resource را همزمان مدیریت کند.
مثلاً برنامهای که همزمان به یک فایل و یک اتصال دیگر نیاز دارد.
🔹 مدیریت چند Resource
میتوانیم داخل یک Context Manager از
حالا:
در اینجا:
🔹 چرا
چون ممکن است تعداد Resourceها ثابت نباشد:
حالا:
هر تعداد فایل که در لیست باشد،
⚠️ نکته مهم
ترکیب این دو زمانی مفید است که یک Context Manager خودش نیاز به مدیریت چند Resource داشته باشد.
🧠 خلاصه
🎯 تمرین
یک Context Manager به نام
لیستی از نام فایلها دریافت کند.
همه فایلها را با
لیست فایلهای بازشده را با
بعد از خروج از
پست ۱۲۹ از دوره جامع Python 🐍
Context Manager با مدیریت چند Resource
گاهی یک Context Manager خودش باید چند Resource را همزمان مدیریت کند.
مثلاً برنامهای که همزمان به یک فایل و یک اتصال دیگر نیاز دارد.
🔹 مدیریت چند Resource
میتوانیم داخل یک Context Manager از
ExitStack استفاده کنیم:from contextlib import contextmanager
from contextlib import ExitStack
@contextmanager
def resources():
with ExitStack() as stack:
file = stack.enter_context(open("data.txt", "w"))
print("Resources opened")
yield file
print("Resources closing")
حالا:
with resources() as file:
file.write("Hello Python")
در اینجا:
resources()
↓
ExitStack
↓
باز شدن Resourceها
↓
yield
↓
کد داخل with
↓
cleanup
🔹 چرا
ExitStack داخل Context Manager؟چون ممکن است تعداد Resourceها ثابت نباشد:
@contextmanager
def open_files(file_names):
with ExitStack() as stack:
files = []
for name in file_names:
file = stack.enter_context(open(name, "w"))
files.append(file)
yield files
حالا:
files = ["a.txt", "b.txt", "c.txt"]
with open_files(files) as opened_files:
for file in opened_files:
file.write("Hello")
هر تعداد فایل که در لیست باشد،
ExitStack آنها را مدیریت میکند.⚠️ نکته مهم
@contextmanager ساختار Context Manager را ساده میکند.ExitStack هم برای مدیریت چند Resource پویا بسیار مناسب است.ترکیب این دو زمانی مفید است که یک Context Manager خودش نیاز به مدیریت چند Resource داشته باشد.
🧠 خلاصه
@contextmanager
↓
ساخت Context Manager ساده
+
ExitStack
↓
مدیریت چند Resource
↓
cleanup خودکار
🎯 تمرین
یک Context Manager به نام
open_files بنویس که:لیستی از نام فایلها دریافت کند.
همه فایلها را با
ExitStack باز کند.لیست فایلهای بازشده را با
yield برگرداند.بعد از خروج از
with، همه فایلها خودکار بسته شوند.پست ۱۲۹ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۳۰
Context Manager با
تا اینجا Context Manager را با
حالا یک نکته مهم دیگر: میتوانیم یک کلاس Context Manager بسازیم که علاوه بر مدیریت ورود و خروج، اطلاعات یا وضعیت داخلی خودش را هم نگه دارد.
🔹 ساخت Context Manager کلاسی
استفاده:
خروجی:
🔹 چرا
در:
مقداری که
پس:
باعث میشود خود شیء را داخل
🔹 مدیریت خطا
اگر داخل
اگر خطایی رخ ندهد:
⚠️ نکته مهم
اگر
اما اگر
پس
🧠 خلاصه
🎯 تمرین
یک کلاس
نام فایل را در
در
خود فایل را با
در
استفاده:
پست ۱۳۰ از دوره جامع Python 🐍
Context Manager با
__enter__ و __exit__ در کلاسهاتا اینجا Context Manager را با
@contextmanager و ExitStack دیدیم.حالا یک نکته مهم دیگر: میتوانیم یک کلاس Context Manager بسازیم که علاوه بر مدیریت ورود و خروج، اطلاعات یا وضعیت داخلی خودش را هم نگه دارد.
🔹 ساخت Context Manager کلاسی
class Database:
def __init__(self, name):
self.name = name
def __enter__(self):
print(f"Connecting to {self.name}")
return self
def __exit__(self, exc_type, exc_value, traceback):
print(f"Closing {self.name}")
استفاده:
with Database("MyDB") as db:
print(f"Using {db.name}")خروجی:
Connecting to MyDB
Using MyDB
Closing MyDB
🔹 چرا
return self؟در:
with Database("MyDB") as db:مقداری که
__enter__() برمیگرداند، داخل db قرار میگیرد.پس:
return self
باعث میشود خود شیء را داخل
db داشته باشیم.🔹 مدیریت خطا
__exit__() اطلاعات خطا را دریافت میکند:def __exit__(self, exc_type, exc_value, traceback):
if exc_type is not None:
print("An error occurred")
print("Closing database")
اگر داخل
with خطایی رخ دهد، exc_type و exc_value اطلاعات آن خطا را در اختیارمان قرار میدهند.اگر خطایی رخ ندهد:
exc_type = None
exc_value = None
traceback = None
⚠️ نکته مهم
اگر
__exit__() مقدار True برگرداند، Exception سرکوب میشود.def __exit__(self, exc_type, exc_value, traceback):
print("Closing database")
return True
اما اگر
False یا None برگرداند، خطا به بیرون منتقل میشود.پس
return True را فقط زمانی استفاده کن که عمداً میخواهی خطا را مدیریت و متوقف کنی.🧠 خلاصه
__enter__() → ورود و آمادهسازی
yield/as → در اختیار قرار دادن Resource
__exit__() → خروج و Cleanup
🎯 تمرین
یک کلاس
FileManager بساز که:نام فایل را در
__init__ دریافت کند.در
__enter__() فایل را باز کند.خود فایل را با
return برگرداند.در
__exit__() فایل را ببندد.استفاده:
with FileManager("data.txt") as file:
file.write("Hello Python")پست ۱۳۰ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۱۳۱
Context Manager برای فایلها با
در پست قبل یک Context Manager کلاسی ساختیم.
حالا آن را روی فایلها پیاده میکنیم تا ببینیم چطور میتوانیم باز کردن و بستن فایل را خودمان مدیریت کنیم.
🔹 ساخت
حالا میتوانیم از آن با
ترتیب اجرا:
🔹 اگر داخل
حتی اگر داخل
قبل از خروج، فایل بسته میشود.
بنابراین
⚠️ نکته مهم
در Python برای کار معمول با فایلها نیازی نیست خودمان چنین کلاسی بنویسیم.
روش استاندارد همان است:
این مثال فقط برای درک بهتر نحوه کار Context Manager است.
🧠 خلاصه
🎯 تمرین
کلاس
اما فایل همچنان در
پست ۱۳۱ از دوره جامع Python 🐍
Context Manager برای فایلها با
__enter__ و __exit__در پست قبل یک Context Manager کلاسی ساختیم.
حالا آن را روی فایلها پیاده میکنیم تا ببینیم چطور میتوانیم باز کردن و بستن فایل را خودمان مدیریت کنیم.
🔹 ساخت
FileManagerclass FileManager:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
self.file = None
def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_value, traceback):
self.file.close()
حالا میتوانیم از آن با
with استفاده کنیم:with FileManager("data.txt", "w") as file:
file.write("Hello Python")ترتیب اجرا:
__enter__()
↓
باز شدن فایل
↓
کد داخل with
↓
__exit__()
↓
بسته شدن فایل
🔹 اگر داخل
with خطا رخ دهد؟حتی اگر داخل
with خطایی ایجاد شود، __exit__() اجرا میشود:with FileManager("data.txt", "w") as file:
file.write("Hello")
raise ValueError("Something went wrong")قبل از خروج، فایل بسته میشود.
بنابراین
__exit__() محل مناسبی برای cleanup است.⚠️ نکته مهم
در Python برای کار معمول با فایلها نیازی نیست خودمان چنین کلاسی بنویسیم.
روش استاندارد همان است:
with open("data.txt", "w") as file:
file.write("Hello Python")این مثال فقط برای درک بهتر نحوه کار Context Manager است.
🧠 خلاصه
__enter__() → باز کردن Resource
with → استفاده از Resource
__exit__() → cleanup و بستن Resource
🎯 تمرین
کلاس
FileManager را طوری تغییر بده که اگر داخل with خطایی رخ داد، پیام زیر را چاپ کند:An error occurred
اما فایل همچنان در
__exit__() بسته شود.پست ۱۳۱ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۳۲
Context Manager و مدیریت خطا در
در پست قبل دیدیم که
حالا میخواهیم از اطلاعات خطا داخل
🔹 اطلاعات خطا در
متد
این پارامترها شامل:
اگر خطایی رخ نداده باشد، هر سه مقدار
🔹 بررسی وجود خطا
استفاده:
خروجی:
🔹 جلوگیری از انتشار خطا
اگر
در این حالت برنامه بعد از
⚠️ نکته مهم
اگر فقط میخواهیم خطا را مشاهده کنیم و اجازه دهیم Exception به بیرون منتقل شود، نباید
اما:
یعنی:
🧠 خلاصه
🎯 تمرین کامل
یک Context Manager به نام
در
اگر هیچ خطایی رخ نداد، در
اگر
پیام خطا را چاپ کند.
خطا را با
اگر Exception دیگری رخ داد:
پیام
خطا را به بیرون منتقل کند.
کد اولیه:
حالا این دو حالت را تست کن:
حالت اول
خروجی مورد انتظار:
حالت دوم
در این حالت باید:
نمایش داده شود و
پست ۱۳۲ از دوره جامع Python 🐍
Context Manager و مدیریت خطا در
__exit__در پست قبل دیدیم که
__exit__() حتی هنگام رخ دادن خطا هم اجرا میشود.حالا میخواهیم از اطلاعات خطا داخل
__exit__() استفاده کنیم.🔹 اطلاعات خطا در
__exit__متد
__exit__() سه پارامتر مهم دریافت میکند:def __exit__(self, exc_type, exc_value, traceback):
این پارامترها شامل:
exc_type → نوع Exception
exc_value → پیام Exception
traceback → اطلاعات محل رخ دادن خطا
اگر خطایی رخ نداده باشد، هر سه مقدار
None هستند.🔹 بررسی وجود خطا
class MyContext:
def __enter__(self):
print("Start")
def __exit__(self, exc_type, exc_value, traceback):
if exc_type is not None:
print("Error:", exc_value)
print("Cleanup")
استفاده:
with MyContext():
print("Working...")
raise ValueError("Invalid value")
خروجی:
Start
Working...
Error: Invalid value
Cleanup
🔹 جلوگیری از انتشار خطا
اگر
__exit__() مقدار True برگرداند، Exception دیگر به بیرون منتقل نمیشود:def __exit__(self, exc_type, exc_value, traceback):
if exc_type is not None:
print("Error handled")
return True
در این حالت برنامه بعد از
with ادامه پیدا میکند.⚠️ نکته مهم
اگر فقط میخواهیم خطا را مشاهده کنیم و اجازه دهیم Exception به بیرون منتقل شود، نباید
True برگردانیم.def __exit__(self, exc_type, exc_value, traceback):
print("Cleanup")
اما:
return True
یعنی:
این Exception را مدیریت کردم؛ دیگر آن را به بیرون منتقل نکن.
🧠 خلاصه
exc_type → نوع خطا
exc_value → اطلاعات خطا
traceback → محل رخ دادن خطا
return True → خطا سرکوب میشود
return None → خطا ادامه پیدا میکند
🎯 تمرین کامل
یک Context Manager به نام
SafeContext بساز که رفتار زیر را داشته باشد:در
__enter__() پیام زیر را چاپ کند:Context started
اگر هیچ خطایی رخ نداد، در
__exit__() پیام زیر را چاپ کند:Context finished
اگر
ValueError رخ داد:پیام خطا را چاپ کند.
خطا را با
return True مدیریت کند.اگر Exception دیگری رخ داد:
پیام
Unknown error را چاپ کند.خطا را به بیرون منتقل کند.
کد اولیه:
class SafeContext:
def __enter__(self):
# کد را کامل کن
pass
def __exit__(self, exc_type, exc_value, traceback):
# کد را کامل کن
pass
حالا این دو حالت را تست کن:
حالت اول
with SafeContext():
print("Working...")
raise ValueError("Invalid value")
خروجی مورد انتظار:
Context started
Working...
Error: Invalid value
حالت دوم
with SafeContext():
print("Working...")
raise TypeError("Wrong type")
در این حالت باید:
Context started
Working...
Unknown error
نمایش داده شود و
TypeError همچنان به بیرون منتقل شود.پست ۱۳۲ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۳۳
ساخت Context Manager با
در پستهای قبل Context Manager را با کلاس و
Python روش سادهتری هم دارد: دکوراتور
🔹 ساخت Context Manager
استفاده:
خروجی:
کد قبل از
🔹 برگرداندن مقدار با
میتوانیم یک مقدار را در اختیار
استفاده:
خروجی:
مقدار
🔹 مدیریت خطا
میتوانیم
حالا:
خروجی:
⚠️ نکته مهم
ساختار کلی:
🧠 خلاصه
🎯 تمرین
یک Context Manager به نام
قبل از
خطاهای
در هر شرایطی در
داخل
✅ پاسخ کامل تمرین
خروجی:
اگر داخل
خروجی:
اینجا
پست ۱۳۳ از دوره جامع Python 🐍
ساخت Context Manager با
contextlib.contextmanagerدر پستهای قبل Context Manager را با کلاس و
__enter__() و __exit__() ساختیم.Python روش سادهتری هم دارد: دکوراتور
@contextmanager.🔹 ساخت Context Manager
from contextlib import contextmanager
@contextmanager
def my_context():
print("Start")
yield
print("End")
استفاده:
with my_context():
print("Working...")
خروجی:
Start
Working...
End
کد قبل از
yield هنگام ورود اجرا میشود و کد بعد از yield هنگام خروج.🔹 برگرداندن مقدار با
yieldمیتوانیم یک مقدار را در اختیار
with قرار دهیم:from contextlib import contextmanager
@contextmanager
def connection():
print("Connecting...")
data = "Database"
yield data
print("Connection closed")
استفاده:
with connection() as db:
print("Using:", db)
خروجی:
Connecting...
Using: Database
Connection closed
مقدار
yield داخل متغیر db قرار میگیرد.🔹 مدیریت خطا
میتوانیم
yield را داخل try/except قرار دهیم:from contextlib import contextmanager
@contextmanager
def safe_context():
print("Start")
try:
yield
except ValueError as error:
print("Error:", error)
finally:
print("Cleanup")
حالا:
with safe_context():
print("Working...")
raise ValueError("Invalid value")
خروجی:
Start
Working...
Error: Invalid value
Cleanup
⚠️ نکته مهم
ساختار کلی:
@contextmanager
def my_context():
# setup
try:
yield
except Exception:
# مدیریت خطا
pass
finally:
# cleanup
pass
yield نقطهای است که اجرای Context Manager موقتاً متوقف میشود و کد داخل with اجرا میشود.🧠 خلاصه
@contextmanager → ساخت ساده Context Manager
yield → اجرای بخش داخلی with
try/except → مدیریت خطا
finally → cleanup
🎯 تمرین
یک Context Manager به نام
database بساز که:قبل از
yield چاپ کند:Connecting...
خطاهای
ValueError را با پیام زیر مدیریت کند:Invalid value
در هر شرایطی در
finally چاپ کند:Connection closed
داخل
with این کد اجرا شود:with database():
print("Query running...")
✅ پاسخ کامل تمرین
from contextlib import contextmanager
@contextmanager
def database():
print("Connecting...")
try:
yield
except ValueError:
print("Invalid value")
finally:
print("Connection closed")
with database():
print("Query running...")
خروجی:
Connecting...
Query running...
Connection closed
اگر داخل
with خطای ValueError ایجاد کنیم:with database():
print("Query running...")
raise ValueError("Bad query")
خروجی:
Connecting...
Query running...
Invalid value
Connection closed
اینجا
except خطا را مدیریت میکند و finally در هر حالت اجرا میشود.پست ۱۳۳ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۳۴
نادیده گرفتن خطاهای مشخص با
گاهی میدانیم یک Exception خاص ممکن است رخ دهد و میخواهیم فقط همان خطا را نادیده بگیریم.
برای این کار میتوانیم از
🔹 استفاده ساده
اگر فایل وجود نداشته باشد،
🔹 فقط Exception مشخص نادیده گرفته میشود
مثلاً:
خروجی:
اما اگر Exception دیگری رخ دهد،
مثلاً:
اینجا
🔹 چند Exception
میتوانیم چند نوع خطا را مشخص کنیم:
در این حالت فقط
⚠️ نکته مهم
وقتی نیاز داریم خطا را بررسی، ثبت یا پردازش کنیم،
اما وقتی فقط میخواهیم یک خطای مشخص را نادیده بگیریم،
🧠 خلاصه
🎯 تمرین
کدی بنویس که با
برنامه باید حتی اگر فایل وجود نداشت، به
✅ پاسخ کامل تمرین
اگر فایل
نمایش داده میشود و
اگر فایل وجود داشته باشد، محتوای آن چاپ میشود و سپس:
نمایش داده میشود.
پست ۱۳۴ از دوره جامع Python 🐍
نادیده گرفتن خطاهای مشخص با
contextlib.suppressگاهی میدانیم یک Exception خاص ممکن است رخ دهد و میخواهیم فقط همان خطا را نادیده بگیریم.
برای این کار میتوانیم از
suppress() در ماژول contextlib استفاده کنیم.🔹 استفاده ساده
from contextlib import suppress
with suppress(FileNotFoundError):
open("missing.txt")
print("Program continues")
اگر فایل وجود نداشته باشد،
FileNotFoundError نادیده گرفته میشود و برنامه ادامه پیدا میکند:Program continues
🔹 فقط Exception مشخص نادیده گرفته میشود
مثلاً:
from contextlib import suppress
with suppress(ValueError):
number = int("abc")
print("Done")
خروجی:
Done
اما اگر Exception دیگری رخ دهد،
suppress() آن را نادیده نمیگیرد.مثلاً:
with suppress(ValueError):
result = 10 / 0
اینجا
ZeroDivisionError رخ میدهد و همچنان منتشر میشود.🔹 چند Exception
میتوانیم چند نوع خطا را مشخص کنیم:
from contextlib import suppress
with suppress(ValueError, TypeError):
value = int("abc")
در این حالت فقط
ValueError یا TypeError نادیده گرفته میشوند.⚠️ نکته مهم
suppress() جایگزین try/except در همه شرایط نیست.وقتی نیاز داریم خطا را بررسی، ثبت یا پردازش کنیم،
try/except مناسبتر است.اما وقتی فقط میخواهیم یک خطای مشخص را نادیده بگیریم،
suppress() کد را سادهتر میکند.🧠 خلاصه
suppress(Exception)
↓
اجرای کد
↓
Exception مشخص؟
↓
نادیده گرفتن خطا
↓
ادامه برنامه
🎯 تمرین
کدی بنویس که با
suppress() خطای FileNotFoundError را نادیده بگیرد:from contextlib import suppress
with suppress(FileNotFoundError):
# فایل data.txt را باز کن
print("Finished")
برنامه باید حتی اگر فایل وجود نداشت، به
Finished برسد.✅ پاسخ کامل تمرین
from contextlib import suppress
with suppress(FileNotFoundError):
file = open("data.txt", "r")
print(file.read())
print("Finished")
اگر فایل
data.txt وجود نداشته باشد:Finished
نمایش داده میشود و
FileNotFoundError نادیده گرفته میشود.اگر فایل وجود داشته باشد، محتوای آن چاپ میشود و سپس:
Finished
نمایش داده میشود.
پست ۱۳۴ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۳۵
Context Manager اختیاری با
گاهی میخواهیم یک بخش از برنامه در بعضی شرایط داخل
برای این حالت میتوانیم از
🔹
مثلاً:
خروجی:
🔹 استفاده با مقدار
خروجی:
یعنی مقدار دادهشده مستقیماً در متغیر
🔥 مثال کاربردی
فرض کنیم گاهی میخواهیم فایل را باز کنیم و گاهی از یک فایل موجود استفاده کنیم.
اینجا
⚠️ بنابراین مسئولیت بستن فایل همچنان با برنامهنویس است.
🔹 چرا
فرض کنید یک تابع گاهی باید Context Manager داشته باشد و گاهی نه.
بهجای اینکه دو مسیر کاملاً متفاوت بنویسیم، میتوانیم یک Context Manager انتخاب کنیم:
این الگو در کدهای قابل تنظیم و کتابخانهها کاربرد دارد.
🧠 خلاصه
و:
مقدار
🎯 تمرین
کدی بنویس که اگر:
بود، از
اگر مقدار
پست ۱۳۵ از دوره جامع Python 🐍
Context Manager اختیاری با
nullcontext()گاهی میخواهیم یک بخش از برنامه در بعضی شرایط داخل
with اجرا شود و در بعضی شرایط نه.برای این حالت میتوانیم از
nullcontext() در ماژول contextlib استفاده کنیم.🔹
nullcontext() چیست؟nullcontext() یک Context Manager است که هیچ کار خاصی انجام نمیدهد؛ اما اجازه میدهد در هر دو حالت از ساختار with استفاده کنیم.مثلاً:
from contextlib import nullcontext
use_context = True
context = nullcontext() if use_context else nullcontext()
with context:
print("Code is running")
خروجی:
Code is running
🔹 استفاده با مقدار
nullcontext() میتواند یک مقدار را هم در اختیار as قرار دهد:from contextlib import nullcontext
with nullcontext("Python") as value:
print(value)
خروجی:
Python
یعنی مقدار دادهشده مستقیماً در متغیر
value قرار میگیرد.🔥 مثال کاربردی
فرض کنیم گاهی میخواهیم فایل را باز کنیم و گاهی از یک فایل موجود استفاده کنیم.
from contextlib import nullcontext
file = open("data.txt", "r")
context = nullcontext(file)
with context as f:
print(f.read())
file.close()
اینجا
nullcontext(file) باعث میشود with از فایل موجود استفاده کند، بدون اینکه خودش آن را مدیریت یا در پایان ببندد.⚠️ بنابراین مسئولیت بستن فایل همچنان با برنامهنویس است.
🔹 چرا
nullcontext() مفید است؟فرض کنید یک تابع گاهی باید Context Manager داشته باشد و گاهی نه.
بهجای اینکه دو مسیر کاملاً متفاوت بنویسیم، میتوانیم یک Context Manager انتخاب کنیم:
from contextlib import nullcontext
enabled = False
context = open("data.txt") if enabled else nullcontext()
with context as resource:
print("Running...")
این الگو در کدهای قابل تنظیم و کتابخانهها کاربرد دارد.
🧠 خلاصه
nullcontext()
↓
Context Manager بدون عملیات خاص
↓
مناسب برای حالتهای اختیاری
و:
with nullcontext(value) as x:
...
مقدار
value را در اختیار x قرار میدهد.🎯 تمرین
کدی بنویس که اگر:
use_resource = True
بود، از
nullcontext("Python") استفاده کند و مقدار را چاپ کند.اگر مقدار
use_resource برابر False بود، باز هم برنامه بدون خطا اجرا شود.پست ۱۳۵ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۱۳۶
تغییر موقت خروجی
گاهی میخواهیم خروجیهایی که با
برای این کار میتوانیم از
🔹 استفاده ساده
در این حالت، خروجی
محتوای فایل:
🔹 چرا
بهصورت عادی:
خروجی به
اما داخل:
خروجی استاندارد به فایل هدایت میشود.
بنابراین:
بهجای ترمینال، داخل فایل نوشته میشود.
🔹 بعد از
تغییر مسیر فقط موقتی است:
محتوای
و در ترمینال:
یعنی بعد از خروج از
🔥 مثال کاربردی
فرض کنید یک تابع داریم که چندین
میتوانیم بدون تغییر دادن خود تابع، خروجی آن را داخل فایل ذخیره کنیم:
حالا تمام خروجی تابع داخل
⚠️ نکته مهم
بنابراین برای پیامهای خطا که معمولاً از
وجود دارد.
این دو را در ادامه بررسی میکنیم.
🧠 خلاصه
🎯 تمرین
کد زیر را کامل کن تا خروجی تابع داخل
بعد فایل
پست ۱۳۶ از دوره جامع Python 🐍
تغییر موقت خروجی
print() با redirect_stdout()گاهی میخواهیم خروجیهایی که با
print() تولید میشوند، بهجای نمایش در ترمینال، داخل یک فایل یا مقصد دیگری نوشته شوند.برای این کار میتوانیم از
redirect_stdout() در ماژول contextlib استفاده کنیم.🔹 استفاده ساده
from contextlib import redirect_stdout
with open("output.txt", "w") as file:
with redirect_stdout(file):
print("Hello Python")
print("This goes into the file")
در این حالت، خروجی
print() داخل output.txt نوشته میشود.محتوای فایل:
Hello Python
This goes into the file
🔹 چرا
print() دیگر در ترمینال نمایش داده نمیشود؟بهصورت عادی:
print("Hello")خروجی به
stdout یا همان خروجی استاندارد ارسال میشود.اما داخل:
with redirect_stdout(file):
خروجی استاندارد به فایل هدایت میشود.
بنابراین:
print("Hello")بهجای ترمینال، داخل فایل نوشته میشود.
🔹 بعد از
with چه اتفاقی میافتد؟تغییر مسیر فقط موقتی است:
from contextlib import redirect_stdout
with open("output.txt", "w") as file:
with redirect_stdout(file):
print("Inside")
print("Outside")
محتوای
output.txt:Inside
و در ترمینال:
Outside
یعنی بعد از خروج از
with، stdout به حالت قبلی برمیگردد.🔥 مثال کاربردی
فرض کنید یک تابع داریم که چندین
print() انجام میدهد:def show_report():
print("Report")
print("Total: 100")
print("Status: OK")
میتوانیم بدون تغییر دادن خود تابع، خروجی آن را داخل فایل ذخیره کنیم:
from contextlib import redirect_stdout
def show_report():
print("Report")
print("Total: 100")
print("Status: OK")
with open("report.txt", "w") as file:
with redirect_stdout(file):
show_report()
حالا تمام خروجی تابع داخل
report.txt قرار میگیرد.⚠️ نکته مهم
redirect_stdout() فقط stdout را تغییر میدهد.بنابراین برای پیامهای خطا که معمولاً از
stderr استفاده میکنند، ابزار دیگری مثل:redirect_stderr()
وجود دارد.
این دو را در ادامه بررسی میکنیم.
🧠 خلاصه
stdout
↓
print()
↓
redirect_stdout()
↓
فایل یا مقصد دیگر
redirect_stdout() تغییر مسیر stdout را فقط در محدودهی with انجام میدهد.🎯 تمرین
کد زیر را کامل کن تا خروجی تابع داخل
result.txt ذخیره شود:from contextlib import redirect_stdout
def calculate():
print("Calculation started")
print("Result: 42")
with open("result.txt", "w") as file:
# خروجی calculate را به فایل هدایت کن
...
بعد فایل
result.txt را باز کن و محتوای آن را بررسی کن.پست ۱۳۶ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۳۷
تغییر مسیر خطاها با
در پست قبل یاد گرفتیم
اما خطاها معمولاً از مسیر دیگری به نام
برای تغییر مسیر
🔹 استفاده ساده
حالا پیام داخل
محتوای فایل:
🔹 تفاوت
بهصورت ساده:
مثلاً:
این دو پیام از دو مسیر متفاوت ارسال میشوند.
🔹 تغییر مسیر موقت
مثل
فقط
بعد از خروج از
🔥 مثال کاربردی
فرض کنید تابعی داریم که پیام خطا تولید میکند:
میتوانیم فقط خطاها را داخل فایل ذخیره کنیم:
در نتیجه:
و داخل
⚠️ نکته مهم
مثلاً:
این
برای مدیریت Exception باید از
🧠 خلاصه
هر دو تغییر مسیر را میتوان بهصورت موقت و داخل
🎯 تمرین
کد زیر را کامل کن تا پیام خطا داخل
پست ۱۳۷ از دوره جامع Python 🐍
تغییر مسیر خطاها با
redirect_stderr()در پست قبل یاد گرفتیم
redirect_stdout() میتواند خروجی print() را موقتاً به یک فایل یا مقصد دیگر هدایت کند.اما خطاها معمولاً از مسیر دیگری به نام
stderr ارسال میشوند.برای تغییر مسیر
stderr میتوانیم از redirect_stderr() استفاده کنیم.🔹 استفاده ساده
from contextlib import redirect_stderr
import sys
with open("errors.txt", "w") as file:
with redirect_stderr(file):
print("This is an error message", file=sys.stderr)
حالا پیام داخل
errors.txt نوشته میشود.محتوای فایل:
This is an error message
🔹 تفاوت
stdout و stderrبهصورت ساده:
stdout → خروجی عادی برنامه
stderr → خطاها و پیامهای خطا
مثلاً:
import sys
print("Normal output")
print("Error message", file=sys.stderr)
این دو پیام از دو مسیر متفاوت ارسال میشوند.
🔹 تغییر مسیر موقت
مثل
redirect_stdout()، تغییر مسیر stderr فقط داخل with انجام میشود:import sys
from contextlib import redirect_stderr
with open("errors.txt", "w") as file:
with redirect_stderr(file):
print("Error 1", file=sys.stderr)
print("Normal output")
print("Error 2", file=sys.stderr)
فقط
Error 1 داخل فایل قرار میگیرد.بعد از خروج از
with، stderr به حالت قبلی برمیگردد.🔥 مثال کاربردی
فرض کنید تابعی داریم که پیام خطا تولید میکند:
import sys
def process():
print("Processing...")
print("Something went wrong", file=sys.stderr)
میتوانیم فقط خطاها را داخل فایل ذخیره کنیم:
from contextlib import redirect_stderr
with open("errors.txt", "w") as file:
with redirect_stderr(file):
process()
در نتیجه:
ترمینال:
Processing...
و داخل
errors.txt:Something went wrong
⚠️ نکته مهم
redirect_stderr() خودِ Exceptionها را مدیریت یا حذف نمیکند.مثلاً:
from contextlib import redirect_stderr
with open("errors.txt", "w") as file:
with redirect_stderr(file):
raise ValueError("Invalid value")
این
ValueError همچنان یک Exception واقعی است و برنامه را متوقف میکند؛ redirect_stderr() فقط مسیر stderr را تغییر میدهد.برای مدیریت Exception باید از
try/except یا ابزارهای مناسب دیگر استفاده کنیم.🧠 خلاصه
stdout → خروجی عادی
stderr → خروجی خطا
redirect_stdout() → تغییر مسیر stdout
redirect_stderr() → تغییر مسیر stderr
هر دو تغییر مسیر را میتوان بهصورت موقت و داخل
with انجام داد.🎯 تمرین
کد زیر را کامل کن تا پیام خطا داخل
errors.txt ذخیره شود:import sys
from contextlib import redirect_stderr
def check():
print("Checking...")
print("Invalid input", file=sys.stderr)
with open("errors.txt", "w") as file:
# stderr را به فایل هدایت کن
...
پست ۱۳۷ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۳۸
مدیریت همزمان
تا اینجا یاد گرفتیم:
و برای تغییر مسیر آنها از:
استفاده کردیم.
حالا میتوانیم هر دو را همزمان به مقصدهای مختلف هدایت کنیم.
🔹 هدایت به دو فایل مختلف
بعد از اجرای برنامه:
و
🔹 چرا از چند Context Manager استفاده کردیم؟
در Python میتوان چند Context Manager را در یک
بنابراین:
یعنی هر دو Context Manager در یک بلوک فعال هستند.
🔥 مثال کاربردی
فرض کنید یک برنامه گزارش اجرا تولید میکند:
میتوانیم خروجی عادی و خطاها را جداگانه ذخیره کنیم:
نتیجه:
و:
⚠️ نکته مهم
ترتیب Context Managerها در
مثلاً:
ورود به Contextها به ترتیب نوشتهشدن انجام میشود و هنگام خروج، برعکس خارج میشوند.
یعنی:
این همان رفتار LIFO است که در
🧠 خلاصه
یعنی چند Context Manager را میتوان همزمان مدیریت کرد.
در این مثال:
خروجی عادی و پیامهای خطا در دو مسیر جدا قرار میگیرند.
🎯 تمرین
کد را کامل کن:
هدف:
و:
پست ۱۳۸ از دوره جامع Python 🐍
مدیریت همزمان
stdout و stderrتا اینجا یاد گرفتیم:
stdout → خروجی عادی
stderr → پیامهای خطا
و برای تغییر مسیر آنها از:
redirect_stdout()
redirect_stderr()
استفاده کردیم.
حالا میتوانیم هر دو را همزمان به مقصدهای مختلف هدایت کنیم.
🔹 هدایت به دو فایل مختلف
import sys
from contextlib import redirect_stdout, redirect_stderr
with open("output.txt", "w") as output:
with open("errors.txt", "w") as errors:
with redirect_stdout(output), redirect_stderr(errors):
print("Program started")
print("Something went wrong", file=sys.stderr)
بعد از اجرای برنامه:
output.txt:Program started
و
errors.txt:Something went wrong
🔹 چرا از چند Context Manager استفاده کردیم؟
در Python میتوان چند Context Manager را در یک
with قرار داد:with context1, context2:
...
بنابراین:
with redirect_stdout(output), redirect_stderr(errors):
یعنی هر دو Context Manager در یک بلوک فعال هستند.
🔥 مثال کاربردی
فرض کنید یک برنامه گزارش اجرا تولید میکند:
import sys
def run():
print("Starting...")
print("Loading data...")
print("Invalid record", file=sys.stderr)
print("Finished")
میتوانیم خروجی عادی و خطاها را جداگانه ذخیره کنیم:
from contextlib import redirect_stdout, redirect_stderr
with open("output.txt", "w") as output:
with open("errors.txt", "w") as errors:
with redirect_stdout(output), redirect_stderr(errors):
run()
نتیجه:
output.txt
----------------
Starting...
Loading data...
Finished
و:
errors.txt
----------------
Invalid record
⚠️ نکته مهم
ترتیب Context Managerها در
with اهمیت دارد.مثلاً:
with context1, context2:
...
ورود به Contextها به ترتیب نوشتهشدن انجام میشود و هنگام خروج، برعکس خارج میشوند.
یعنی:
ورود:
context1
↓
context2
خروج:
context2
↓
context1
این همان رفتار LIFO است که در
ExitStack هم دیدیم.🧠 خلاصه
with context1, context2:
...
یعنی چند Context Manager را میتوان همزمان مدیریت کرد.
در این مثال:
with redirect_stdout(output), redirect_stderr(errors):
خروجی عادی و پیامهای خطا در دو مسیر جدا قرار میگیرند.
🎯 تمرین
کد را کامل کن:
import sys
from contextlib import redirect_stdout, redirect_stderr
def program():
print("Start")
print("Warning", file=sys.stderr)
print("Done")
with open("output.txt", "w") as output:
with open("errors.txt", "w") as errors:
# هر دو مسیر را به فایل مناسب هدایت کن
...
هدف:
output.txt
Start
Done
و:
errors.txt
Warning
پست ۱۳۸ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۳۹
تغییر موقت ورودی استاندارد با
در پست قبل با
برای ورودی استاندارد نیز چیزی به نام
اگر بخواهیم موقتاً ورودی
🔹
بهصورت معمول، وقتی مینویسیم:
ورودی از
میتوانیم
🔹 تغییر
برای اینکه این تغییر فقط داخل
حالا میتوانیم از آن استفاده کنیم:
اگر
باشد، خروجی:
خواهد بود.
🔹 چند ورودی از فایل
فرض کنید فایل
باشد.
میتوانیم بنویسیم:
خروجی:
🔥 کاربرد مهم: تست برنامه
این روش برای برنامههایی که با
مثلاً:
فایل:
و اجرای برنامه:
خروجی:
بدون اینکه کاربر
⚠️ محدودیت مهم
این روش ورودی تعاملی واقعی را شبیهسازی نمیکند.
وقتی:
باشد،
بنابراین برای برنامههایی که نیاز به تعامل مداوم با کاربر دارند، مناسب نیست.
مثلاً اگر فایل فقط دو خط داشته باشد و برنامه سه بار
در بار سوم دیگر ورودی کافی وجود ندارد و ممکن است
⚠️ یک نکته دیگر
تغییر
به همین دلیل در Context Manager بالا، مقدار قبلی ذخیره میشود:
و در
حتی اگر داخل
🧠 خلاصه
برای تغییر موقت
و در پایان:
را انجام دهیم.
نکته: برخلاف
🎯 تمرین
فایل
سپس Context Manager را کامل کن تا برنامه زیر ورودیهایش را از فایل دریافت کند:
خروجی باید باشد:
پست ۱۳۹ از دوره جامع Python 🐍
تغییر موقت ورودی استاندارد با
sys.stdinدر پست قبل با
stdout و stderr آشنا شدیم.برای ورودی استاندارد نیز چیزی به نام
redirect_stdin() در contextlib وجود ندارد.اگر بخواهیم موقتاً ورودی
input() را از یک فایل یا منبع دیگر دریافت کنیم، میتوانیم sys.stdin را تغییر دهیم.🔹
sys.stdin چیست؟sys.stdin همان ورودی استاندارد برنامه است.بهصورت معمول، وقتی مینویسیم:
name = input("Name: ")ورودی از
sys.stdin خوانده میشود.میتوانیم
sys.stdin را موقتاً به یک فایل وصل کنیم.🔹 تغییر
stdinبرای اینکه این تغییر فقط داخل
with انجام شود، میتوانیم یک Context Manager ساده بسازیم:import sys
from contextlib import contextmanager
@contextmanager
def redirect_stdin(file):
old_stdin = sys.stdin
sys.stdin = file
try:
yield
finally:
sys.stdin = old_stdin
حالا میتوانیم از آن استفاده کنیم:
with open("input.txt", "r") as file:
with redirect_stdin(file):
name = input()
print(name)اگر
input.txt شامل:Ali
باشد، خروجی:
Ali
خواهد بود.
🔹 چند ورودی از فایل
فرض کنید فایل
input.txt شامل:Ali
25
باشد.
میتوانیم بنویسیم:
with open("input.txt", "r") as file:
with redirect_stdin(file):
name = input()
age = input()
print(name)
print(age)خروجی:
Ali
25
🔥 کاربرد مهم: تست برنامه
این روش برای برنامههایی که با
input() کار میکنند، در تستهای ساده مفید است.مثلاً:
def calculate():
a = int(input())
b = int(input())
print(a + b)
فایل:
10
20
و اجرای برنامه:
with open("input.txt", "r") as file:
with redirect_stdin(file):
calculate()خروجی:
30
بدون اینکه کاربر
10 و 20 را دستی وارد کند.⚠️ محدودیت مهم
این روش ورودی تعاملی واقعی را شبیهسازی نمیکند.
وقتی:
sys.stdin = file
باشد،
input() از فایل میخواند، نه از کیبورد.بنابراین برای برنامههایی که نیاز به تعامل مداوم با کاربر دارند، مناسب نیست.
مثلاً اگر فایل فقط دو خط داشته باشد و برنامه سه بار
input() اجرا کند:a = input()
b = input()
c = input()
در بار سوم دیگر ورودی کافی وجود ندارد و ممکن است
EOFError رخ دهد.⚠️ یک نکته دیگر
تغییر
stdin فقط باید موقت باشد.به همین دلیل در Context Manager بالا، مقدار قبلی ذخیره میشود:
old_stdin = sys.stdin
و در
finally دوباره برگردانده میشود:sys.stdin = old_stdin
حتی اگر داخل
with خطایی رخ دهد، stdin به حالت قبلی برمیگردد.🧠 خلاصه
sys.stdin → ورودی استاندارد
sys.stdout → خروجی استاندارد
sys.stderr → خروجی خطا
برای تغییر موقت
stdin میتوانیم:old_stdin = sys.stdin
sys.stdin = file
و در پایان:
sys.stdin = old_stdin
را انجام دهیم.
نکته: برخلاف
redirect_stdout() و redirect_stderr()، در contextlib تابع آمادهای به نام redirect_stdin() نداریم و باید چنین Context Managerای را خودمان بسازیم یا از ابزارهای مناسب تست استفاده کنیم.🎯 تمرین
فایل
input.txt را با این محتوا بساز:10
20
سپس Context Manager را کامل کن تا برنامه زیر ورودیهایش را از فایل دریافت کند:
def calculate():
a = int(input())
b = int(input())
print(a + b)
خروجی باید باشد:
30
پست ۱۳۹ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۴۰
تغییر موقت پوشه کاری با
گاهی برنامه لازم دارد برای مدت کوتاهی در یک پوشه خاص کار کند و بعد از اتمام عملیات، به پوشه قبلی برگردد.
در Python میتوانیم از
🔹 استفاده ساده
اگر پوشه
یعنی:
🔹 چرا
فرض کنید:
میتوانیم موقتاً وارد
داخل
🔹 بازگشت خودکار
اگر خطایی هم رخ دهد، مسیر قبلی بازگردانده میشود:
بعد از خروج از
⚠️ محدودیت مهم: تغییر مسیر سراسری
نکته مهم این است که CWD متعلق به کل Process است، نه یک تابع یا Thread خاص.
مثلاً:
تا زمانی که داخل
در این حالت Python فایل را نسبت به:
جستوجو میکند.
🔥 مشکل در Threadها
فرض کنیم دو Thread داریم:
اگر
چون CWD متعلق به Thread اول نیست؛ وضعیت کل Process تغییر کرده است.
بنابراین در برنامههای چندنخی، تغییر CWD میتواند باعث رفتارهای غیرقابلپیشبینی شود.
🔹 حتی توابع دیگر هم تحت تأثیر قرار میگیرند
مثلاً:
حالا:
تابع
یعنی تغییر CWD میتواند روی کدهای دیگری که از مسیر نسبی استفاده میکنند نیز اثر بگذارد.
✅ راهکار بهتر در بسیاری از موارد
بهجای تغییر CWD، میتوانیم مسیر فایل را مستقیماً مشخص کنیم:
در این روش، تابع به CWD سراسری وابسته نیست.
🔹 تفاوت با
میتوانیم مستقیماً بنویسیم:
اما در این حالت باید خودمان مسیر قبلی را ذخیره و بعداً برگردانیم.
پس تغییر مسیر موقت و قابلبازگشت است؛ اما همچنان خاصیت سراسری CWD را دارد.
🧠 خلاصه
⚠️ در کدهای چندنخی یا کدهایی که نباید وضعیت سراسری برنامه را تغییر دهند، بهتر است تا حد امکان از مسیرهای صریح با
🎯 تمرین
ساختار زیر را در نظر بگیر:
برنامهای بنویس که:
مسیر فعلی را چاپ کند.
با
بعد از خروج از
باید مشاهده کنی که مسیر بعد از
پست ۱۴۰ از دوره جامع Python 🐍
تغییر موقت پوشه کاری با
contextlib.chdir()گاهی برنامه لازم دارد برای مدت کوتاهی در یک پوشه خاص کار کند و بعد از اتمام عملیات، به پوشه قبلی برگردد.
در Python میتوانیم از
chdir() در contextlib استفاده کنیم.contextlib.chdir()از Python 3.11 اضافه شده است.
🔹 استفاده ساده
from contextlib import chdir
import os
print(os.getcwd())
with chdir("data"):
print(os.getcwd())
print(os.getcwd())
اگر پوشه
data وجود داشته باشد:C:\project
C:\project\data
C:\project
یعنی:
قبل از with → پوشه اصلی
داخل with → پوشه data
بعد از with → پوشه اصلی
🔹 چرا
chdir() مفید است؟فرض کنید:
project/
├── main.py
└── data/
├── users.txt
└── products.txt
میتوانیم موقتاً وارد
data شویم:from contextlib import chdir
with chdir("data"):
with open("users.txt", "r") as file:
print(file.read())
داخل
with، مسیر نسبی users.txt نسبت به پوشه data بررسی میشود.🔹 بازگشت خودکار
اگر خطایی هم رخ دهد، مسیر قبلی بازگردانده میشود:
from contextlib import chdir
try:
with chdir("data"):
print("Inside data")
raise ValueError("Something went wrong")
except ValueError:
print("Error handled")
بعد از خروج از
with، CWD دوباره به مسیر قبلی برمیگردد.⚠️ محدودیت مهم: تغییر مسیر سراسری
نکته مهم این است که CWD متعلق به کل Process است، نه یک تابع یا Thread خاص.
مثلاً:
from contextlib import chdir
import os
with chdir("data"):
print(os.getcwd())
تا زمانی که داخل
with هستیم، هر کدی که از مسیر نسبی استفاده کند، تغییر مسیر را میبیند:open("file.txt")در این حالت Python فایل را نسبت به:
data/file.txt
جستوجو میکند.
🔥 مشکل در Threadها
فرض کنیم دو Thread داریم:
def worker_a():
os.chdir("folder_a")
def worker_b():
open("file.txt")
اگر
worker_a مسیر کاری را تغییر دهد، worker_b هم ممکن است مسیر جدید را ببیند.چون CWD متعلق به Thread اول نیست؛ وضعیت کل Process تغییر کرده است.
بنابراین در برنامههای چندنخی، تغییر CWD میتواند باعث رفتارهای غیرقابلپیشبینی شود.
🔹 حتی توابع دیگر هم تحت تأثیر قرار میگیرند
مثلاً:
def load_config():
return open("config.json")
حالا:
from contextlib import chdir
with chdir("data"):
load_config()
تابع
load_config() هیچ اطلاعی از data ندارد، اما فایل را نسبت به پوشه جدید جستوجو میکند.یعنی تغییر CWD میتواند روی کدهای دیگری که از مسیر نسبی استفاده میکنند نیز اثر بگذارد.
✅ راهکار بهتر در بسیاری از موارد
بهجای تغییر CWD، میتوانیم مسیر فایل را مستقیماً مشخص کنیم:
from pathlib import Path
base = Path("data")
file_path = base / "config.json"
with open(file_path) as file:
print(file.read())
در این روش، تابع به CWD سراسری وابسته نیست.
🔹 تفاوت با
os.chdir()میتوانیم مستقیماً بنویسیم:
import os
os.chdir("data")
اما در این حالت باید خودمان مسیر قبلی را ذخیره و بعداً برگردانیم.
contextlib.chdir() این کار را بهصورت Context Manager انجام میدهد:from contextlib import chdir
with chdir("data"):
...
پس تغییر مسیر موقت و قابلبازگشت است؛ اما همچنان خاصیت سراسری CWD را دارد.
🧠 خلاصه
CWD
↓
متعلق به کل Process
↓
همه کدهای استفادهکننده از مسیر نسبی آن را میبینند
chdir(path)
↓
تغییر موقت CWD
↓
اجرای کد
↓
بازگشت خودکار به مسیر قبلی
⚠️ در کدهای چندنخی یا کدهایی که نباید وضعیت سراسری برنامه را تغییر دهند، بهتر است تا حد امکان از مسیرهای صریح با
pathlib استفاده کنیم.🎯 تمرین
ساختار زیر را در نظر بگیر:
project/
├── main.py
└── files/
└── data.txt
برنامهای بنویس که:
مسیر فعلی را چاپ کند.
با
chdir() وارد files شود.data.txt را باز کند و محتوایش را چاپ کند.بعد از خروج از
with دوباره مسیر فعلی را چاپ کند.باید مشاهده کنی که مسیر بعد از
with به مسیر قبلی برگشته است.پست ۱۴۰ از دوره جامع Python 🐍
1
🐍 آموزش جامع Python — پست ۱۴۱
کار با مسیرها با
تا اینجا برای کار با مسیرها از رشتههایی مثل:
و همچنین
اما در Python یک روش مدرنتر و خواناتر برای کار با مسیرها وجود دارد:
🔹 ساخت یک مسیر
ابتدا
خروجی:
🔹 ساخت مسیرهای تو در تو
بهجای چسباندن رشتهها با
خروجی:
این
🔹 ساخت پوشههای تو در تو
فرض کنیم میخواهیم این ساختار را ایجاد کنیم:
میتوانیم بنویسیم:
اینجا:
یعنی اگر پوشههای والد وجود نداشته باشند، آنها را هم بساز.
بنابراین اگر هیچکدام از این پوشهها وجود نداشته باشند:
هر سه پوشه ساخته میشوند.
گزینه:
یعنی اگر پوشهها از قبل وجود داشته باشند، Python خطا ندهد.
پس ترکیب:
برای ساخت پوشههای تودرتو بسیار کاربردی است.
🔹 تفاوت
این دو گزینه کار متفاوتی انجام میدهند:
مثلاً:
حتی اگر
🔹 بررسی وجود مسیر
با
نتیجه:
یا:
🔹 فایل است یا پوشه؟
اگر
🔹 ساخت یک پوشه ساده
اگر فقط یک پوشه را بخواهیم ایجاد کنیم:
در این حالت چون فقط خود
🔹 نام فایل و پسوند
فرض کنیم:
خروجی:
یعنی:
⚠️ نکته مهم
میتوانیم از آن برای:
فایلها
پوشهها
مسیرهای نسبی
مسیرهای مطلق
ترکیب مسیرها
ساخت پوشههای تودرتو
استفاده کنیم.
همچنین استفاده از
🧠 خلاصه
برای ساخت پوشههای تودرتو:
🎯 تمرین
کدی بنویس که:
مسیر
حتی اگر
اگر پوشهها از قبل وجود داشتند، خطا ندهد.
مسیر فایل
نام فایل و پسوند آن را چاپ کند.
شروع:
پست ۱۴۱ از دوره جامع Python 🐍
کار با مسیرها با
pathlibتا اینجا برای کار با مسیرها از رشتههایی مثل:
"data/config.json"
و همچنین
os استفاده کردیم.اما در Python یک روش مدرنتر و خواناتر برای کار با مسیرها وجود دارد:
pathlib
🔹 ساخت یک مسیر
ابتدا
Path را import میکنیم:from pathlib import Path
path = Path("data")
print(path)
خروجی:
data
Path مسیر را بهصورت یک شیء در اختیار ما قرار میدهد.🔹 ساخت مسیرهای تو در تو
بهجای چسباندن رشتهها با
+، میتوانیم از / برای ترکیب مسیرها استفاده کنیم:from pathlib import Path
base = Path("project")
file_path = base / "data" / "users.txt"
print(file_path)
خروجی:
project/data/users.txt
این
/ در pathlib به معنی تقسیم نیست؛ برای ترکیب مسیرها استفاده میشود.🔹 ساخت پوشههای تو در تو
فرض کنیم میخواهیم این ساختار را ایجاد کنیم:
project/
└── data/
└── users/
میتوانیم بنویسیم:
from pathlib import Path
path = Path("project/data/users")
path.mkdir(parents=True, exist_ok=True)
اینجا:
parents=True
یعنی اگر پوشههای والد وجود نداشته باشند، آنها را هم بساز.
بنابراین اگر هیچکدام از این پوشهها وجود نداشته باشند:
project
└── data
└── users
هر سه پوشه ساخته میشوند.
گزینه:
exist_ok=True
یعنی اگر پوشهها از قبل وجود داشته باشند، Python خطا ندهد.
پس ترکیب:
mkdir(parents=True, exist_ok=True)
برای ساخت پوشههای تودرتو بسیار کاربردی است.
🔹 تفاوت
parents=True و exist_ok=Trueاین دو گزینه کار متفاوتی انجام میدهند:
parents=True
→ پوشههای والد را هم ایجاد کن
exist_ok=True
→ اگر پوشه از قبل وجود داشت، خطا نده
مثلاً:
Path("project/data/users").mkdir(
parents=True,
exist_ok=True
)حتی اگر
project و data وجود نداشته باشند، Python مسیر را ایجاد میکند.🔹 بررسی وجود مسیر
با
exists() میتوانیم بررسی کنیم مسیر وجود دارد یا نه:from pathlib import Path
path = Path("data")
print(path.exists())
نتیجه:
True
یا:
False
🔹 فایل است یا پوشه؟
Path متدهای مختلفی برای بررسی نوع مسیر دارد:from pathlib import Path
path = Path("data")
print(path.is_file())
print(path.is_dir())
اگر
data یک پوشه باشد:False
True
🔹 ساخت یک پوشه ساده
اگر فقط یک پوشه را بخواهیم ایجاد کنیم:
from pathlib import Path
path = Path("data")
path.mkdir(exist_ok=True)
در این حالت چون فقط خود
data را میسازیم، نیازی به parents=True نداریم.🔹 نام فایل و پسوند
فرض کنیم:
from pathlib import Path
path = Path("data/users.txt")
print(path.name)
print(path.stem)
print(path.suffix)
خروجی:
users.txt
users
.txt
یعنی:
name → نام کامل فایل
stem → نام فایل بدون پسوند
suffix → پسوند فایل
⚠️ نکته مهم
pathlib فقط مخصوص فایلها نیست.میتوانیم از آن برای:
فایلها
پوشهها
مسیرهای نسبی
مسیرهای مطلق
ترکیب مسیرها
ساخت پوشههای تودرتو
استفاده کنیم.
همچنین استفاده از
Path باعث میشود کد مدیریت مسیرها خواناتر و قابلحملتر باشد.🧠 خلاصه
from pathlib import Path
path = Path("data")
path.exists() # وجود دارد؟
path.is_file() # فایل است؟
path.is_dir() # پوشه است؟
path.mkdir() # ساخت پوشه
path.name # نام کامل
path.stem # نام بدون پسوند
path.suffix # پسوند
برای ساخت پوشههای تودرتو:
path.mkdir(
parents=True,
exist_ok=True
)
🎯 تمرین
کدی بنویس که:
مسیر
project/data/users را ایجاد کند.حتی اگر
project و data وجود نداشتند، آنها را هم بسازد.اگر پوشهها از قبل وجود داشتند، خطا ندهد.
مسیر فایل
users.json را داخل پوشه users بسازد.نام فایل و پسوند آن را چاپ کند.
شروع:
from pathlib import Path
users_dir = Path("project/data/users")
پست ۱۴۱ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۴۲
خواندن و نوشتن فایل با
در پست قبل با
حالا میتوانیم با
🔹 نوشتن در فایل با
اگر فایل وجود نداشته باشد، ساخته میشود.
⚠️ اما اگر پوشه
🔹 ساخت پوشه والد قبل از فایل
برای اطمینان، میتوانیم ابتدا پوشه والد فایل را بسازیم:
اینجا:
پوشه والد فایل را برمیگرداند:
و:
پوشه
اگر پوشههای والد بیشتری داشته باشیم،
مثلاً:
ساختار زیر ایجاد میشود:
🔹 خواندن فایل با
بعد از نوشتن میتوانیم فایل را بخوانیم:
خروجی:
🔹 نوشتن چند خط
میتوانیم از
محتوای فایل:
🔹 خواندن همه محتوا
خروجی:
⚠️ نکته مهم درباره
برای فایلهای متنی، مخصوصاً زمانی که فارسی داریم، بهتر است encoding را مشخص کنیم:
مثلاً:
خروجی:
🔹 تفاوت با
قبلاً برای کار با فایلها میتوانستیم از:
استفاده کنیم.
با
و:
استفاده کنیم.
⚠️ نکته مهم
در پایان محتوای فایل:
خواهد بود.
برای اضافهکردن محتوا به انتهای فایل، بعداً روش مناسب آن را بررسی میکنیم.
🧠 خلاصه
یعنی:
🎯 تمرین
برنامهای بنویس که:
مسیر
تمام پوشههای والد را در صورت نیاز بسازد.
داخل فایل نام و سن یک کاربر را بنویسد.
فایل را دوباره بخواند.
محتوای آن را چاپ کند.
مثلاً:
پست ۱۴۲ از دوره جامع Python 🐍
خواندن و نوشتن فایل با
pathlibدر پست قبل با
Path و ساخت مسیرها آشنا شدیم.حالا میتوانیم با
Path مستقیماً فایل متنی را بخوانیم و بنویسیم.🔹 نوشتن در فایل با
write_text()from pathlib import Path
file = Path("data/message.txt")
file.write_text("Hello Python", encoding="utf-8")
اگر فایل وجود نداشته باشد، ساخته میشود.
⚠️ اما اگر پوشه
data وجود نداشته باشد، write_text() خودش آن را ایجاد نمیکند و با خطا مواجه میشویم.🔹 ساخت پوشه والد قبل از فایل
برای اطمینان، میتوانیم ابتدا پوشه والد فایل را بسازیم:
from pathlib import Path
file = Path("data/message.txt")
file.parent.mkdir(parents=True, exist_ok=True)
file.write_text("Hello Python", encoding="utf-8")
اینجا:
file.parent
پوشه والد فایل را برمیگرداند:
data
و:
file.parent.mkdir(
parents=True,
exist_ok=True
)
پوشه
data را ایجاد میکند.اگر پوشههای والد بیشتری داشته باشیم،
parents=True همه آنها را ایجاد میکند.مثلاً:
from pathlib import Path
file = Path("project/data/users/info.txt")
file.parent.mkdir(parents=True, exist_ok=True)
file.write_text("Ali", encoding="utf-8")
ساختار زیر ایجاد میشود:
project/
└── data/
└── users/
└── info.txt
🔹 خواندن فایل با
read_text()بعد از نوشتن میتوانیم فایل را بخوانیم:
from pathlib import Path
file = Path("data/message.txt")
text = file.read_text(encoding="utf-8")
print(text)
خروجی:
Hello Python
🔹 نوشتن چند خط
میتوانیم از
\n برای ایجاد خط جدید استفاده کنیم:from pathlib import Path
file = Path("data/users.txt")
file.parent.mkdir(parents=True, exist_ok=True)
file.write_text(
"Ali\nSara\nReza",
encoding="utf-8"
)
محتوای فایل:
Ali
Sara
Reza
🔹 خواندن همه محتوا
read_text() کل محتوای فایل را بهصورت یک str برمیگرداند:text = file.read_text(encoding="utf-8")
print(type(text))
خروجی:
<class 'str'>
⚠️ نکته مهم درباره
encodingبرای فایلهای متنی، مخصوصاً زمانی که فارسی داریم، بهتر است encoding را مشخص کنیم:
encoding="utf-8"
مثلاً:
from pathlib import Path
file = Path("data/message.txt")
file.parent.mkdir(parents=True, exist_ok=True)
file.write_text(
"سلام Python",
encoding="utf-8"
)
print(file.read_text(encoding="utf-8"))
خروجی:
سلام Python
🔹 تفاوت با
open()قبلاً برای کار با فایلها میتوانستیم از:
open()
استفاده کنیم.
با
pathlib برای عملیات ساده متنی میتوانیم مستقیماً از:file.write_text(...)
و:
file.read_text(...)
استفاده کنیم.
⚠️ نکته مهم
write_text() محتوای قبلی فایل را جایگزین میکند:file.write_text("First", encoding="utf-8")
file.write_text("Second", encoding="utf-8")در پایان محتوای فایل:
Second
خواهد بود.
برای اضافهکردن محتوا به انتهای فایل، بعداً روش مناسب آن را بررسی میکنیم.
🧠 خلاصه
from pathlib import Path
file = Path("data/message.txt")
file.parent.mkdir(parents=True, exist_ok=True)
file.write_text("Hello", encoding="utf-8")
text = file.read_text(encoding="utf-8")
یعنی:
file.parent → پوشه والد فایل
mkdir() → ساخت پوشه
write_text → نوشتن متن
read_text → خواندن متن
🎯 تمرین
برنامهای بنویس که:
مسیر
project/data/users/info.txt را ایجاد کند.تمام پوشههای والد را در صورت نیاز بسازد.
داخل فایل نام و سن یک کاربر را بنویسد.
فایل را دوباره بخواند.
محتوای آن را چاپ کند.
مثلاً:
Name: Ali
Age: 25
پست ۱۴۲ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۴۳
اضافه کردن محتوا به فایل با حالت
در پست قبل یاد گرفتیم
اما گاهی نمیخواهیم اطلاعات قبلی حذف شود؛ میخواهیم متن جدید را به انتهای فایل اضافه کنیم.
برای این کار از حالت:
استفاده میکنیم.
🔹 اضافه کردن متن به فایل
با
اگر فایل قبلاً این محتوا را داشته باشد:
بعد از اجرای کد:
خواهد شد.
🔹 تفاوت
حالت
محتوای قبلی حذف میشود.
اما حالت
محتوای قبلی باقی میماند و متن جدید به انتهای فایل اضافه میشود.
🔹 یک مثال کاربردی
فرض کنیم میخواهیم کاربران را یکییکی به فایل اضافه کنیم:
محتوای فایل:
هر بار که فایل با حالت
🔹 چرا از
این روش برای مدیریت فایلها امنتر و استانداردتر است.
⚠️ نکته مهم درباره
اگر میخواهیم هر مقدار در یک خط جدید قرار بگیرد، باید خط جدید ایجاد کنیم:
اگر
نتیجه:
اما:
نتیجه:
🧠 خلاصه
مثلاً برای اضافه کردن:
🎯 تمرین
برنامهای بنویس که:
فایل
عبارت
دوباره همین برنامه را اجرا کن و تفاوت را ببین.
در هر اجرا، متن در یک خط جدید اضافه شود.
کد را طوری بنویس که اطلاعات قبلی فایل حذف نشود.
پست ۱۴۳ از دوره جامع Python 🐍
اضافه کردن محتوا به فایل با حالت
appendدر پست قبل یاد گرفتیم
write_text() محتوای فایل را جایگزین میکند.اما گاهی نمیخواهیم اطلاعات قبلی حذف شود؛ میخواهیم متن جدید را به انتهای فایل اضافه کنیم.
برای این کار از حالت:
"a"
استفاده میکنیم.
🔹 اضافه کردن متن به فایل
با
Path.open() میتوانیم فایل را در حالت append باز کنیم:from pathlib import Path
file = Path("data/users.txt")
with file.open("a", encoding="utf-8") as f:
f.write("Ali\n")
اگر فایل قبلاً این محتوا را داشته باشد:
Sara
Reza
بعد از اجرای کد:
Sara
Reza
Ali
خواهد شد.
🔹 تفاوت
w و aحالت
w برای نوشتن و جایگزین کردن محتوا است:with file.open("w", encoding="utf-8") as f:
f.write("Ali\n")محتوای قبلی حذف میشود.
اما حالت
a برای اضافه کردن است:with file.open("a", encoding="utf-8") as f:
f.write("Ali\n")محتوای قبلی باقی میماند و متن جدید به انتهای فایل اضافه میشود.
🔹 یک مثال کاربردی
فرض کنیم میخواهیم کاربران را یکییکی به فایل اضافه کنیم:
from pathlib import Path
file = Path("data/users.txt")
with file.open("a", encoding="utf-8") as f:
f.write("Ali\n")
with file.open("a", encoding="utf-8") as f:
f.write("Sara\n")
with file.open("a", encoding="utf-8") as f:
f.write("Reza\n")
محتوای فایل:
Ali
Sara
Reza
هر بار که فایل با حالت
a باز میشود، اطلاعات جدید به انتهای آن اضافه میشود.🔹 چرا از
with استفاده میکنیم؟with file.open("a", encoding="utf-8") as f:
f.write("Ali\n")with باعث میشود بعد از پایان کار، فایل بهدرستی بسته شود.این روش برای مدیریت فایلها امنتر و استانداردتر است.
⚠️ نکته مهم درباره
\nاگر میخواهیم هر مقدار در یک خط جدید قرار بگیرد، باید خط جدید ایجاد کنیم:
f.write("Ali\n")اگر
\n نگذاریم:f.write("Ali")
f.write("Sara")نتیجه:
AliSara
اما:
f.write("Ali\n")
f.write("Sara\n")نتیجه:
Ali
Sara
🧠 خلاصه
"w" → نوشتن و جایگزین کردن محتوا
"a" → اضافه کردن محتوا به انتهای فایل
"r" → خواندن فایل
مثلاً برای اضافه کردن:
with file.open("a", encoding="utf-8") as f:
f.write("New data\n")🎯 تمرین
برنامهای بنویس که:
فایل
data/log.txt را باز کند.عبارت
Program started را به انتهای فایل اضافه کند.دوباره همین برنامه را اجرا کن و تفاوت را ببین.
در هر اجرا، متن در یک خط جدید اضافه شود.
کد را طوری بنویس که اطلاعات قبلی فایل حذف نشود.
پست ۱۴۳ از دوره جامع Python 🐍
🐍 آموزش جامع Python — پست ۱۴۴
خواندن فایل خطبهخط با
در پستهای قبل یاد گرفتیم کل محتوای فایل را با
اما همیشه لازم نیست کل فایل را یکجا بخوانیم.
گاهی میخواهیم فایل را خطبهخط پردازش کنیم.
🔹
متد
اگر فایل این باشد:
خروجی:
هر بار که
🔹
اگر فایل:
باشد، نتیجه چیزی شبیه این است:
دقت کن
🔹 پردازش خطبهخط با
در بسیاری از مواقع لازم نیست از
خود فایل قابل پیمایش است:
این روش برای خواندن فایلهای بزرگ بسیار مناسبتر است، چون همه خطوط را یکجا داخل یک لیست قرار نمیدهد.
🔹 حذف
اگر نمیخواهیم خط جدید همراه متن باقی بماند:
اگر فایل:
باشد، هر خط بهصورت تمیز پردازش میشود.
⚠️ تفاوت مهم
برای فایلهای کوچک، هر سه روش میتوانند مناسب باشند.
برای فایلهای بزرگ، پیمایش خطبهخط معمولاً انتخاب مناسبتری است.
🧠 یک مثال کاربردی
فرض کنیم فایل شامل نمرهها باشد:
میتوانیم آنها را خطبهخط بخوانیم:
خروجی:
اینجا:
متن خط را تمیز میکند و:
آن را به عدد صحیح تبدیل میکند.
🧠 خلاصه
یک خط.
تمام خطوط به شکل لیست.
پردازش خطبهخط.
🎯 تمرین
فایلی به نام:
بساز و داخل آن قرار بده:
سپس برنامهای بنویس که:
فایل را باز کند.
اعداد را خطبهخط بخواند.
هر خط را به
مجموع اعداد را محاسبه کند.
مجموع را چاپ کند.
خروجی مورد انتظار:
پست ۱۴۴ از دوره جامع Python 🐍
خواندن فایل خطبهخط با
readlines() و readline()در پستهای قبل یاد گرفتیم کل محتوای فایل را با
read_text() بخوانیم.اما همیشه لازم نیست کل فایل را یکجا بخوانیم.
گاهی میخواهیم فایل را خطبهخط پردازش کنیم.
🔹
readline()متد
readline() یک خط از فایل را میخواند:from pathlib import Path
file = Path("data/users.txt")
with file.open("r", encoding="utf-8") as f:
print(f.readline())
print(f.readline())
اگر فایل این باشد:
Ali
Sara
Reza
خروجی:
Ali
Sara
هر بار که
readline() را اجرا میکنیم، به خط بعدی میرویم.🔹
readlines()readlines() تمام خطوط فایل را میخواند و آنها را داخل یک لیست قرار میدهد:from pathlib import Path
file = Path("data/users.txt")
with file.open("r", encoding="utf-8") as f:
lines = f.readlines()
print(lines)
اگر فایل:
Ali
Sara
Reza
باشد، نتیجه چیزی شبیه این است:
['Ali\n', 'Sara\n', 'Reza\n']
دقت کن
\n نیز ممکن است داخل رشته هر خط وجود داشته باشد.🔹 پردازش خطبهخط با
forدر بسیاری از مواقع لازم نیست از
readlines() استفاده کنیم.خود فایل قابل پیمایش است:
from pathlib import Path
file = Path("data/users.txt")
with file.open("r", encoding="utf-8") as f:
for line in f:
print(line)
این روش برای خواندن فایلهای بزرگ بسیار مناسبتر است، چون همه خطوط را یکجا داخل یک لیست قرار نمیدهد.
🔹 حذف
\n با strip()اگر نمیخواهیم خط جدید همراه متن باقی بماند:
from pathlib import Path
file = Path("data/users.txt")
with file.open("r", encoding="utf-8") as f:
for line in f:
print(line.strip())
اگر فایل:
Ali
Sara
Reza
باشد، هر خط بهصورت تمیز پردازش میشود.
⚠️ تفاوت مهم
readline()
→ یک خط را میخواند
readlines()
→ همه خطوط را در یک لیست قرار میدهد
for line in file
→ فایل را خطبهخط پیمایش میکند
برای فایلهای کوچک، هر سه روش میتوانند مناسب باشند.
برای فایلهای بزرگ، پیمایش خطبهخط معمولاً انتخاب مناسبتری است.
🧠 یک مثال کاربردی
فرض کنیم فایل شامل نمرهها باشد:
18
15
20
12
میتوانیم آنها را خطبهخط بخوانیم:
from pathlib import Path
file = Path("data/scores.txt")
with file.open("r", encoding="utf-8") as f:
for line in f:
score = int(line.strip())
print(score)
خروجی:
18
15
20
12
اینجا:
line.strip()
متن خط را تمیز میکند و:
int(...)
آن را به عدد صحیح تبدیل میکند.
🧠 خلاصه
f.readline()
یک خط.
f.readlines()
تمام خطوط به شکل لیست.
for line in f:
پردازش خطبهخط.
🎯 تمرین
فایلی به نام:
data/numbers.txt
بساز و داخل آن قرار بده:
10
20
30
40
سپس برنامهای بنویس که:
فایل را باز کند.
اعداد را خطبهخط بخواند.
هر خط را به
int تبدیل کند.مجموع اعداد را محاسبه کند.
مجموع را چاپ کند.
خروجی مورد انتظار:
100
پست ۱۴۴ از دوره جامع Python 🐍