متغیرهای برنامه پس از پایان اجرا باقی نمیمانند. برای نگهداری یادداشت یا گزارش ساده، میتوانید از فایل متنی و CSV استفاده کنید. در این آموزش با پایتون ۳ یک یادداشت فارسی مینویسیم، خطی به آن اضافه میکنیم و مجموع دقیقههای مطالعه را از CSV میخوانیم.
پیشنیاز: رشته، حلقه، لیست و دیکشنری. اگر هنوز با این مفاهیم راحت نیستید، ابتدا ده تمرین پایتون با پاسخ را انجام دهید. نمونهها کتابخانهٔ خارجی لازم ندارند.
تفاوت حالتهای r، w، a و x چیست؟
rبرای خواندن است؛ اگر فایل وجود نداشته باشد خطا میدهد.wبرای نوشتن است و محتوای قبلی فایل موجود را پاک میکند. فقط روی فایل تمرینی استفاده کنید.aمتن را به انتهای فایل اضافه میکند؛ اگر فایل نباشد آن را میسازد.xفایل تازه میسازد و اگر نام از قبل وجود داشته باشد، بهجای بازنویسی خطا میدهد.
بلوک with فایل را پس از پایان کار، حتی هنگام بروز خطا درون بلوک، میبندد. برای متن فارسی، کدگذاری را صریحاً utf-8 تعیین میکنیم تا به تنظیم پیشفرض سیستم وابسته نباشیم.
مسیر فایل را قابل پیشبینی کنید
مسیر نسبی معمولاً نسبت به پوشهٔ کاری برنامه تفسیر میشود، نه لزوماً محل فایل پایتون. این نمونه کنار خود اسکریپت پوشهٔ practice-output میسازد. کد را در فایل file_practice.py ذخیره کنید؛ __file__ برای اجرای فایل است و در بعضی محیطهای تعاملی یا دفترچهها تعریف نشده است.
from pathlib import Path
import csv
folder = Path(__file__).resolve().parent / "practice-output"
folder.mkdir(exist_ok=True)
note_path = folder / "notes.txt"نوشتن، افزودن و خواندن متن فارسی
این قطعه را زیر کد قبلی قرار دهید. اجرای دوباره، ابتدا یادداشت تمرینی را با حالت w از نو مینویسد و سپس خط دوم را اضافه میکند؛ بنابراین در هر اجرا دو خط خواهید داشت.
# This practice file is replaced on each run.
with note_path.open("w", encoding="utf-8") as file:
file.write("امروز خواندن فایل را تمرین کردم.\n")
with note_path.open("a", encoding="utf-8") as file:
file.write("قدم بعدی: ساخت گزارش CSV\n")
with note_path.open("r", encoding="utf-8") as file:
for line_number, line in enumerate(file, start=1):
print(line_number, line.rstrip("\n"))کاراکتر \n در رشته، خط جدید ایجاد میکند. خواندن با حلقه برای فایلهای بزرگ مناسبتر از بارگذاری همهٔ محتوا با read() است. متد rstrip("\n") در اینجا فقط انتهای خط را برمیدارد تا دستور print خط خالی اضافه ایجاد نکند.
چرا CSV را با split جدا نکنیم؟
در مثال ما نام یکی از درسها HTML, CSS است؛ خود مقدار شامل ویرگول است. جداکردن دستی هر خط با ویرگول، این نام را به دو ستون تبدیل میکند. ماژول استاندارد csv قواعد نقلقول و جداکننده را مدیریت میکند.
ابتدا گزارش تمرینی را بنویسید
هر دیکشنری یک جلسه است. fieldnames نام و ترتیب ستونها را مشخص میکند. هنگام بازکردن فایل CSV، newline="" را میدهیم تا مدیریت پایان خط به ماژول CSV سپرده شود.
sessions = [
{"subject": "Python", "minutes": 20},
{"subject": "HTML, CSS", "minutes": 15},
{"subject": "Python", "minutes": 30},
]
csv_path = folder / "study.csv"
with csv_path.open("w", encoding="utf-8", newline="") as file:
writer = csv.DictWriter(file, fieldnames=["subject", "minutes"])
writer.writeheader()
writer.writerows(sessions)سپس داده را بخوانید و اعتبارسنجی کنید
مقادیر خواندهشده رشتهاند؛ برای جمعزدن باید دقیقهها به عدد صحیح تبدیل شوند. نام ستونها، نام درس، تعداد اضافی ستونها و دقیقهٔ منفی یا نامعتبر را بررسی میکنیم. شمارهٔ ردیف در پیام خطا کمک میکند محل اشکال را پیدا کنید.
total = 0
with csv_path.open("r", encoding="utf-8", newline="") as file:
reader = csv.DictReader(file)
if reader.fieldnames != ["subject", "minutes"]:
raise ValueError("Unexpected CSV columns")
for row_number, row in enumerate(reader, start=2):
if None in row or not row.get("subject", "").strip():
raise ValueError(f"Invalid subject or extra columns at row {row_number}")
try:
minutes = int(row["minutes"])
except (ValueError, TypeError):
raise ValueError(f"Invalid minutes at row {row_number}") from None
if minutes < 0:
raise ValueError(f"Negative minutes at row {row_number}")
total += minutes
print("Total minutes:", total)انتظار داریم خروجی آخر Total minutes: 65 باشد. این یک نمونهٔ آموزشی با دادهٔ مشخص است؛ برای ورودیهای بیرونی بزرگ یا نامطمئن، محدودیت حجم، ستونها و سیاست برخورد با دادهٔ ناقص را متناسب با برنامه تعریف کنید.
خطاهای رایج کار با فایل در پایتون
- خطای FileNotFoundError: نام و مسیر فایل را بررسی کنید. خواندن با r فایل جدید ایجاد نمیکند.
- خطای PermissionError: مسیر ممکن است قابل نوشتن نباشد یا فایل در برنامهای دیگر قفل شده باشد. برای تمرین، پوشهای متعلق به خودتان انتخاب کنید.
- خطای UnicodeDecodeError: کدگذاری فایل با کدگذاری انتخابشده یکسان نیست. منبع فایل را بررسی کنید؛ حذف خطا با نادیدهگرفتن کاراکترها ممکن است داده را خراب کند.
- ستون اول نام عجیبی دارد: بعضی خروجیهای CSV نشان BOM دارند؛ در صورت تأیید UTF-8 با BOM از
utf-8-sigبرای خواندن استفاده کنید. - اعداد جمع نمیشوند: مقدار CSV رشته است. تبدیل عدد و کنترل مقدار خالی را پیش از محاسبه انجام دهید.
دانلود نمونه و تمرین بعدی
کد کامل و راهنمای اجرای پروژه را بگیرید و دستور python file_practice.py را اجرا کنید. فایلهای خروجی آموزشی در اجرای مجدد بازنویسی میشوند؛ دادهٔ واقعی خود را در پوشهٔ خروجی قرار ندهید.
برای تمرین مستقل، بخش خواندن CSV را به تابع جداگانه منتقل کنید و یک فایل کپیشده را بخوانید تا مرحلهٔ نوشتن تغییرات آزمایشی شما را پاک نکند. یک دقیقهٔ نامعتبر، یک ردیف ناقص و یک نام دارای ویرگول امتحان کنید. سپس بهجای مجموع کلی، جمع هر درس را با یک دیکشنری گزارش دهید.
ادامهٔ مسیر یادگیری
فایل برای تمرینهای کوچک مناسب است. برنامهٔ چندکاربره ممکن است به پایگاه داده و کنترل همزمانی نیاز داشته باشد. برای مرور مفاهیم پایه، راهنمای شروع پایتون و برای یادگیری با مدرس، دورهٔ پایتون آکادمی را بررسی کنید.
منابع تکمیلی
جزئیات رفتار حالتهای فایل در راهنمای رسمی ورودی و خروجی پایتون و قواعد CSV در مستندات ماژول csv آمده است. مثال گزارش مطالعه برای این مقاله نوشته شده است.