آموزش برنامه نویسی

پروژه کوچک پایتون با CSV؛ گزارش هزینه ها با کنترل خطا

با داده ساختگی، فایل CSV را بخوانید، مبلغ ها را بررسی کنید و گزارش دسته بندی بسازید؛ کد کامل، خروجی مورد انتظار و تمرین حالت های خطا.

پروژه کوچک پایتون با CSV؛ گزارش هزینه ها با کنترل خطا

برای تمرین مدیریت فایل در پایتون، می توانید از خواندن چند خط متن به ساخت یک گزارش قابل بررسی برسید. در این پروژه کوچک، یک فایل CSV شامل هزینه های آموزشی را می خوانیم، مبلغ هر ردیف را کنترل می کنیم و مجموع هر دسته را در فایل دیگری می نویسیم. داده ها کاملاً ساختگی اند و برنامه هیچ فایل موجودی را بدون اجازه بازنویسی نمی کند. پیش نیاز این تمرین، آشنایی با حلقه، شرط و تابع است.

فایل ورودی را بسازید

یک پوشه تازه بسازید. فایل expenses.csv را با محتوای زیر و کدگذاری UTF-8 ذخیره کنید. عددها در این تمرین انگلیسی و بدون جداکننده هزارگان هستند. سطر اول نام ستون هاست؛ مقدارهای متنی ممکن است فارسی باشند.

category,amount
کتاب,120000
اینترنت,80000
کتاب,50000
رفت وآمد,30000

خروجی مورد انتظار شامل سه دسته است: کتاب با مجموع 170000، اینترنت با 80000 و رفت وآمد با 30000. این انتظار را پیش از اجرای برنامه بنویسید تا بتوانید درستی نتیجه را بررسی کنید. اگر برای خواندن و نوشتن فایل نیاز به مرور دارید، آموزش فایل متن و CSV در پایتون را بخوانید.

خواندن داده با نام ستون ها

DictReader هر ردیف را بر اساس نام ستون ها در اختیار شما می گذارد. مبلغ به طور خودکار عدد نمی شود؛ باید آن را تبدیل و بررسی کنیم. این نمونه از Decimal استفاده می کند تا جمع مقادیر ده دهی به محاسبه ممیز شناور وابسته نباشد. فایل خروجی با حالت x ساخته می شود تا اگر از قبل وجود دارد، بازنویسی نشود.

کد را در report.py کنار فایل ورودی ذخیره کنید:

import csv
from decimal import Decimal, InvalidOperation
from pathlib import Path

def summarize(source):
    totals = {}
    with source.open(encoding="utf-8-sig", newline="") as handle:
        reader = csv.DictReader(handle)
        if reader.fieldnames != ["category", "amount"]:
            raise ValueError("Expected category,amount columns")
        for row in reader:
            line = reader.line_num
            category = (row.get("category") or "").strip()
            if None in row or not category:
                raise ValueError(f"Invalid row at line {line}")
            try:
                amount = Decimal((row.get("amount") or "").strip())
            except InvalidOperation:
                raise ValueError(f"Invalid amount at line {line}") from None
            if not amount.is_finite() or amount < 0:
                raise ValueError(f"Amount must be finite and nonnegative: {line}")
            totals[category] = totals.get(category, Decimal("0")) + amount
    return totals

def write_report(destination, totals):
    with destination.open("x", encoding="utf-8-sig", newline="") as handle:
        writer = csv.writer(handle)
        writer.writerow(["category", "total"])
        for category, total in sorted(totals.items()):
            writer.writerow([category, format(total, "f")])

if __name__ == "__main__":
    folder = Path(__file__).resolve().parent
    try:
        totals = summarize(folder / "expenses.csv")
        write_report(folder / "report.csv", totals)
    except (OSError, ValueError) as error:
        print(f"Could not create report: {error}")
        raise SystemExit(1)
    print("Created report.csv")

اجرا و بررسی خروجی

در محیطی که پایتون نصب است، از داخل پوشه تمرین دستور زیر را اجرا کنید. اگر نام فرمان پایتون در سیستم شما متفاوت است، از همان فرمان نصب شده استفاده کنید.

python report.py

فایل report.csv را باز کنید و مقدار هر دسته را با انتظار اولیه تطبیق دهید. بار دوم باید پیام مربوط به وجود فایل خروجی را ببینید؛ این رفتار عمدی است. برای اجرای دوباره، خروجی قبلی را نگه دارید و نام مقصد را در کد به report-2.csv تغییر دهید. برنامه، خواندن ورودی را پیش از ساخت خروجی تمام می کند؛ بنابراین مبلغ نامعتبر باعث تولید گزارش ظاهراً کامل نمی شود.

چهار حالت خطا را خودتان بسازید

  1. نام یکی از ستون ها را تغییر دهید؛ برنامه باید ساختار ورودی را نامعتبر تشخیص دهد.
  2. به جای یک مبلغ، متن بنویسید؛ پیام باید ردیف مشکل دار را مشخص کند.
  3. یک مبلغ منفی یا NaN وارد کنید؛ داده نامعتبر نباید در جمع نهایی قرار بگیرد.
  4. فایل ورودی را موقتاً با نام دیگری ذخیره کنید؛ برنامه باید خطای دسترسی به ورودی را گزارش کند.

چرا از split برای CSV استفاده نکردیم؟

متن یک ستون ممکن است خودش ویرگول یا خط جدید داشته باشد. ماژول csv قواعد نقل قول و جداکننده را مدیریت می کند، درحالی که جدا کردن ساده رشته با ویرگول همه این حالت ها را پوشش نمی دهد. گزینه newline نیز طبق مستندات ماژول برای خواندن و نوشتن فایل CSV استفاده شده است. utf-8-sig در این نمونه به خواندن فایل های دارای نشان UTF-8 و نوشتن خروجی سازگارتر با برخی ابزارهای صفحه گسترده کمک می کند؛ رفتار نمایش همچنان به نرم افزار خواننده بستگی دارد.

قدم بعدی: پروژه را قابل توضیح کنید

به برنامه امکان فیلتر دسته اضافه کنید یا تعداد ردیف های هر دسته را نیز گزارش دهید. برای هر تغییر، یک ورودی کوچک و نتیجه مورد انتظار بسازید. سپس در یک README توضیح دهید برنامه چه ورودی می گیرد، چه خروجی می دهد و چه داده هایی را رد می کند. این تمرین ادامه ای برای تمرین های پایتون با پاسخ تشریحی و یک نمونه کوچک برای ساخت نمونه کار برنامه نویسی است.

این نمونه برای یادگیری است؛ برای گزارش های واقعی باید قالب داده، کنترل دسترسی و قواعد مجموعه را جدا بررسی کنید. منابع: مستندات رسمی csv و آموزش رسمی خطاها و استثناها.

برای شروع مسیر یادگیری آماده‌ای؟

دوره‌های پروژه‌محور آکادمی گلجام را ببین.

مشاهده دوره‌ها
مشاوره رایگان مشاوره