20-bo‘lim

Amaliy loyiha - Xarajatlar hisoblagichi

Barcha o'rganilgan bilimlarni birlashtirib to'liq ishlaydigan dastur yaratamiz: OOP, SQLite, xatolarni boshqarish, hisobotlar va CSV eksport.

🕑 7 daqiqa o‘qish 📄 521 so‘z 👁 7 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Loyiha haqida
  2. 1-qadam: modellar.py
  3. 2-qadam: baza.py
  4. 3-qadam: hisobot.py
  5. 4-qadam: asosiy.py
  6. Dasturni ishga tushirish
  7. Loyihada nima ishlatildi?
  8. Bundan keyin nima qilish kerak?
  9. Yakuniy xulosa

Tabriklaymiz - siz 19 ta bo'limni yakunladingiz! Endi barcha bilimlarni bitta to'liq ishlaydigan dasturga birlashtiramiz.

Loyiha haqida #

Xarajatlar hisoblagichi - shaxsiy moliyani kuzatish dasturi. U quyidagilarni bajaradi:

  • Xarajat va daromadlarni SQLite bazasiga yozadi
  • Toifalar bo'yicha guruhlaydi
  • Oylik hisobot va matnli diagramma chiqaradi
  • Ma'lumotni CSV faylga eksport qiladi
  • Barcha xatolarni to'g'ri boshqaradi
asosiy.py (menyu) modellar.py Amal, Toifa klasslari baza.py SQLite bilan ishlash hisobot.py Statistika va eksport xarajatlar.db
Loyiha to'rtta modulga bo'lingan - har biri o'z vazifasiga javob beradi

1-qadam: modellar.py #

Python
# modellar.py
"""Loyiha ma'lumot modellari."""

from dataclasses import dataclass, field
from datetime import date
from enum import Enum


class AmalTuri(Enum):
    """Amal turi: daromad yoki xarajat."""
    DAROMAD = "daromad"
    XARAJAT = "xarajat"


TOIFALAR = {
    AmalTuri.XARAJAT: [
        "Oziq-ovqat", "Transport", "Kommunal", "Ta'lim",
        "Sog'liq", "Kiyim", "Ko'ngilochar", "Boshqa",
    ],
    AmalTuri.DAROMAD: ["Oylik", "Qo'shimcha ish", "Sovg'a", "Boshqa"],
}


@dataclass
class Amal:
    """Bitta moliyaviy amal."""

    turi: AmalTuri
    toifa: str
    summa: int
    izoh: str = ""
    sana: date = field(default_factory=date.today)
    id: int | None = None

    def __post_init__(self):
        """Obyekt yaratilgandan keyin tekshiruv."""
        if self.summa <= 0:
            raise ValueError("Summa musbat son bo'lishi kerak")
        if self.toifa not in TOIFALAR[self.turi]:
            ruxsat = ", ".join(TOIFALAR[self.turi])
            raise ValueError(f"Noto'g'ri toifa. Ruxsat etilgan: {ruxsat}")

    @property
    def belgili_summa(self) -> int:
        """Daromad musbat, xarajat manfiy ko'rinishda."""
        return self.summa if self.turi == AmalTuri.DAROMAD else -self.summa

    def __str__(self) -> str:
        belgi = "+" if self.turi == AmalTuri.DAROMAD else "-"
        return (f"{self.sana.strftime('%d.%m.%Y')}  {self.toifa:<14}"
                f"{belgi}{self.summa:>12,} so'm  {self.izoh}")
Enum nima?

Enum - cheklangan qiymatlar to'plami. AmalTuri.XARAJAT yozganingizda muharrir sizga variantlarni ko'rsatadi va "xarjat" kabi imlo xatosi darhol xato beradi. Oddiy satrlar bilan bunday himoya yo'q.

2-qadam: baza.py #

Python
# baza.py
"""SQLite bazasi bilan ishlash qatlami."""

import sqlite3
from contextlib import contextmanager
from datetime import date
from pathlib import Path

from modellar import Amal, AmalTuri

BAZA_YOLI = Path("xarajatlar.db")


@contextmanager
def ulanish():
    """Bazaga ulanadi va yakunda albatta yopadi."""
    aloqa = sqlite3.connect(BAZA_YOLI)
    aloqa.row_factory = sqlite3.Row
    try:
        yield aloqa
        aloqa.commit()
    except Exception:
        aloqa.rollback()
        raise
    finally:
        aloqa.close()


def bazani_tayyorla() -> None:
    """Jadval mavjud bo'lmasa yaratadi."""
    with ulanish() as aloqa:
        aloqa.execute("""
            CREATE TABLE IF NOT EXISTS amallar (
                id     INTEGER PRIMARY KEY AUTOINCREMENT,
                turi   TEXT    NOT NULL,
                toifa  TEXT    NOT NULL,
                summa  INTEGER NOT NULL,
                izoh   TEXT    DEFAULT '',
                sana   TEXT    NOT NULL
            )
        """)
        aloqa.execute("CREATE INDEX IF NOT EXISTS idx_sana ON amallar (sana)")


def amal_qosh(amal: Amal) -> int:
    """Yangi amalni bazaga yozadi va uning id sini qaytaradi."""
    with ulanish() as aloqa:
        kursor = aloqa.execute(
            "INSERT INTO amallar (turi, toifa, summa, izoh, sana) VALUES (?, ?, ?, ?, ?)",
            (amal.turi.value, amal.toifa, amal.summa, amal.izoh, amal.sana.isoformat()),
        )
        return kursor.lastrowid


def amallarni_ol(oy: int | None = None, yil: int | None = None) -> list[Amal]:
    """Amallarni o'qiydi, oy va yil bo'yicha filtrlash mumkin."""
    sorov = "SELECT * FROM amallar"
    parametrlar = []

    if oy and yil:
        sorov += " WHERE strftime('%m', sana) = ? AND strftime('%Y', sana) = ?"
        parametrlar = [f"{oy:02d}", str(yil)]

    sorov += " ORDER BY sana DESC, id DESC"

    with ulanish() as aloqa:
        qatorlar = aloqa.execute(sorov, parametrlar).fetchall()

    return [
        Amal(
            id=qator["id"],
            turi=AmalTuri(qator["turi"]),
            toifa=qator["toifa"],
            summa=qator["summa"],
            izoh=qator["izoh"],
            sana=date.fromisoformat(qator["sana"]),
        )
        for qator in qatorlar
    ]


def amalni_ochir(amal_id: int) -> bool:
    """Amalni o'chiradi, muvaffaqiyat holatini qaytaradi."""
    with ulanish() as aloqa:
        kursor = aloqa.execute("DELETE FROM amallar WHERE id = ?", (amal_id,))
        return kursor.rowcount > 0

3-qadam: hisobot.py #

Python
# hisobot.py
"""Statistika, diagramma va eksport."""

import csv
from collections import defaultdict
from pathlib import Path

from modellar import Amal, AmalTuri

KENGLIK = 58


def sarlavha(matn: str) -> None:
    print("=" * KENGLIK)
    print(f"{matn:^{KENGLIK}}")
    print("=" * KENGLIK)


def umumiy_hisobot(amallar: list[Amal]) -> None:
    """Daromad, xarajat va qoldiqni chiqaradi."""
    daromad = sum(a.summa for a in amallar if a.turi == AmalTuri.DAROMAD)
    xarajat = sum(a.summa for a in amallar if a.turi == AmalTuri.XARAJAT)
    qoldiq = daromad - xarajat

    sarlavha("UMUMIY HISOBOT")
    print(f"{'Jami daromad:':<32}{daromad:>18,} so'm")
    print(f"{'Jami xarajat:':<32}{xarajat:>18,} so'm")
    print("-" * KENGLIK)
    print(f"{'QOLDIQ:':<32}{qoldiq:>18,} so'm")

    if daromad > 0:
        foiz = xarajat / daromad * 100
        print(f"{'Xarajat ulushi:':<32}{foiz:>17.1f} %")
        if foiz > 90:
            print("\n  ! Diqqat: daromadingizning deyarli hammasi sarflanmoqda.")
        elif foiz < 60:
            print("\n  + Ajoyib! Daromadingizning katta qismini tejayapsiz.")
    print("=" * KENGLIK)


def toifalar_diagrammasi(amallar: list[Amal]) -> None:
    """Toifalar bo'yicha matnli ustunli diagramma chizadi."""
    xarajatlar = defaultdict(int)
    for amal in amallar:
        if amal.turi == AmalTuri.XARAJAT:
            xarajatlar[amal.toifa] += amal.summa

    if not xarajatlar:
        print("\nXarajatlar mavjud emas.")
        return

    jami = sum(xarajatlar.values())
    eng_katta = max(xarajatlar.values())

    print()
    sarlavha("TOIFALAR BO'YICHA XARAJATLAR")

    for toifa, summa in sorted(xarajatlar.items(), key=lambda j: j[1], reverse=True):
        foiz = summa / jami * 100
        ustun = "#" * int(summa / eng_katta * 22)
        print(f"{toifa:<14}{summa:>12,}{foiz:>7.1f}%  {ustun}")

    print("-" * KENGLIK)
    print(f"{'JAMI':<14}{jami:>12,}{100.0:>7.1f}%")
    print("=" * KENGLIK)


def csv_eksport(amallar: list[Amal], yol: str = "hisobot.csv") -> Path:
    """Amallarni CSV faylga yozadi."""
    fayl_yoli = Path(yol)

    with open(fayl_yoli, "w", encoding="utf-8", newline="") as fayl:
        yozuvchi = csv.writer(fayl)
        yozuvchi.writerow(["Sana", "Turi", "Toifa", "Summa", "Izoh"])
        for amal in amallar:
            yozuvchi.writerow([
                amal.sana.isoformat(),
                amal.turi.value,
                amal.toifa,
                amal.summa,
                amal.izoh,
            ])

    return fayl_yoli.resolve()

4-qadam: asosiy.py #

Python
# asosiy.py
"""Xarajatlar hisoblagichi - asosiy menyu."""

from datetime import date

import baza
import hisobot
from modellar import Amal, AmalTuri, TOIFALAR


def son_sora(xabar: str, eng_kam: int = 1) -> int:
    """Foydalanuvchidan to'g'ri son kiritilgunicha so'raydi."""
    while True:
        try:
            qiymat = int(input(xabar).replace(" ", "").replace(",", ""))
            if qiymat < eng_kam:
                print(f"  ! Qiymat {eng_kam} dan kichik bo'lmasin.")
                continue
            return qiymat
        except ValueError:
            print("  ! Faqat butun son kiriting.")


def toifa_tanla(turi: AmalTuri) -> str:
    """Toifalar ro'yxatidan bittasini tanlatadi."""
    toifalar = TOIFALAR[turi]

    print("\nToifani tanlang:")
    for tartib, toifa in enumerate(toifalar, start=1):
        print(f"  {tartib}. {toifa}")

    tanlov = son_sora("Raqam: ", eng_kam=1)
    while tanlov > len(toifalar):
        print(f"  ! 1 dan {len(toifalar)} gacha son kiriting.")
        tanlov = son_sora("Raqam: ", eng_kam=1)

    return toifalar[tanlov - 1]


def amal_qoshish(turi: AmalTuri) -> None:
    """Yangi daromad yoki xarajat qo'shadi."""
    nomi = "daromad" if turi == AmalTuri.DAROMAD else "xarajat"
    print(f"\n--- Yangi {nomi} ---")

    toifa = toifa_tanla(turi)
    summa = son_sora("Summa (so'm): ")
    izoh = input("Izoh (ixtiyoriy): ").strip()

    try:
        amal = Amal(turi=turi, toifa=toifa, summa=summa, izoh=izoh)
        yangi_id = baza.amal_qosh(amal)
        print(f"\n  + Saqlandi (#{yangi_id}): {amal}")
    except ValueError as xato:
        print(f"\n  ! Xato: {xato}")


def amallarni_korish() -> None:
    """Barcha amallarni jadval ko'rinishida chiqaradi."""
    amallar = baza.amallarni_ol()

    if not amallar:
        print("\nHali birorta amal kiritilmagan.")
        return

    print()
    hisobot.sarlavha("BARCHA AMALLAR")
    for amal in amallar[:20]:
        print(f"#{amal.id:<4}{amal}")

    if len(amallar) > 20:
        print(f"\n  ... va yana {len(amallar) - 20} ta amal")
    print("=" * hisobot.KENGLIK)


def oylik_hisobot() -> None:
    """Tanlangan oy bo'yicha hisobot."""
    bugun = date.today()
    oy = son_sora(f"Oy raqami (1-12, standart {bugun.month}): ", eng_kam=1)
    yil = son_sora(f"Yil (standart {bugun.year}): ", eng_kam=2000)

    amallar = baza.amallarni_ol(oy=oy, yil=yil)

    if not amallar:
        print(f"\n{oy:02d}.{yil} uchun ma'lumot topilmadi.")
        return

    print(f"\n>>> {oy:02d}.{yil} hisoboti ({len(amallar)} ta amal)\n")
    hisobot.umumiy_hisobot(amallar)
    hisobot.toifalar_diagrammasi(amallar)


def eksport() -> None:
    """Ma'lumotni CSV ga chiqaradi."""
    amallar = baza.amallarni_ol()
    if not amallar:
        print("\nEksport qilish uchun ma'lumot yo'q.")
        return

    yol = hisobot.csv_eksport(amallar)
    print(f"\n  + {len(amallar)} ta amal eksport qilindi:\n    {yol}")


def menyu() -> None:
    """Asosiy menyu sikli."""
    baza.bazani_tayyorla()

    amallar_xaritasi = {
        "1": lambda: amal_qoshish(AmalTuri.XARAJAT),
        "2": lambda: amal_qoshish(AmalTuri.DAROMAD),
        "3": amallarni_korish,
        "4": lambda: hisobot.umumiy_hisobot(baza.amallarni_ol()),
        "5": lambda: hisobot.toifalar_diagrammasi(baza.amallarni_ol()),
        "6": oylik_hisobot,
        "7": eksport,
    }

    while True:
        print("\n" + "=" * hisobot.KENGLIK)
        print(f"{'XARAJATLAR HISOBLAGICHI':^{hisobot.KENGLIK}}")
        print("=" * hisobot.KENGLIK)
        print("  1 - Xarajat qo'shish")
        print("  2 - Daromad qo'shish")
        print("  3 - Barcha amallar")
        print("  4 - Umumiy hisobot")
        print("  5 - Toifalar diagrammasi")
        print("  6 - Oylik hisobot")
        print("  7 - CSV ga eksport")
        print("  0 - Chiqish")

        tanlov = input("\nTanlovingiz: ").strip()

        if tanlov == "0":
            print("\nXayr! Moliyangiz nazoratda bo'lsin.")
            break

        amal = amallar_xaritasi.get(tanlov)
        if amal is None:
            print("  ! Noto'g'ri tanlov.")
            continue

        try:
            amal()
        except Exception as xato:
            print(f"\n  ! Kutilmagan xato: {xato}")


if __name__ == "__main__":
    try:
        menyu()
    except KeyboardInterrupt:
        print("\n\nDastur foydalanuvchi tomonidan to'xtatildi.")

Dasturni ishga tushirish #

Terminal
python asosiy.py
Natija
==========================================================
                 XARAJATLAR HISOBLAGICHI                  
==========================================================
  1 - Xarajat qo'shish
  2 - Daromad qo'shish
  3 - Barcha amallar
  4 - Umumiy hisobot
  5 - Toifalar diagrammasi
  6 - Oylik hisobot
  7 - CSV ga eksport
  0 - Chiqish

Tanlovingiz: 5
Natija
==========================================================
              TOIFALAR BO'YICHA XARAJATLAR                
==========================================================
Oziq-ovqat       1,850,000   41.1%  ######################
Transport          720,000   16.0%  ########
Kommunal           640,000   14.2%  #######
Ta'lim             500,000   11.1%  ######
Ko'ngilochar       380,000    8.4%  ####
Kiyim              260,000    5.8%  ###
Sog'liq            150,000    3.3%  #
----------------------------------------------------------
JAMI             4,500,000  100.0%
==========================================================
Natija
==========================================================
                     UMUMIY HISOBOT                       
==========================================================
Jami daromad:                            7,000,000 so'm
Jami xarajat:                            4,500,000 so'm
----------------------------------------------------------
QOLDIQ:                                  2,500,000 so'm
Xarajat ulushi:                               64.3 %
==========================================================

Loyihada nima ishlatildi? #

Bo'limMavzuLoyihada qayerda
3-4Sintaksis, turlarButun loyiha bo'ylab
5OperatorlarFoiz va qoldiq hisoblash
6Satrlar, f-satrlarJadval formatlash
7-8Ro'yxat, lug'atTOIFALAR, defaultdict
9-10Shartlar, sikllarMenyu sikli, validatsiya
11FunksiyalarBarcha modullar
12Modullar4 ta faylga bo'lish
13Fayllar, CSVEksport funksiyasi
14Xatoliklartry/except, __post_init__
15-16OOPAmal klassi, Enum
17Ilg'or@contextmanager, @property, comprehension
18Standart kutubxonacollections, pathlib, datetime
19Ma'lumotlar bazasiSQLite qatlami
Loyihani kengaytirish

Dasturni o'zingiz rivojlantiring:

  1. Amalni tahrirlash - mavjud yozuvni o'zgartirish imkoniyati.
  2. Byudjet limiti - har bir toifa uchun oylik limit belgilash va oshib ketganda ogohlantirish.
  3. Qidiruv - izoh bo'yicha matnli qidiruv (LIKE ? SQL bilan).
  4. Grafik - matplotlib bilan haqiqiy doiraviy diagramma chizish.
  5. Testlar - unittest bilan modellar.py va hisobot.py uchun testlar yozing.
  6. Valyuta - USD kursini API dan olib, summani ikkala valyutada ko'rsatish.

Bundan keyin nima qilish kerak? #

Veb dasturlash Flask, Django, FastAPI Ma'lumot tahlili Pandas, NumPy, Matplotlib Sun'iy intellekt scikit-learn, PyTorch Avtomatlashtirish Selenium, Telegram botlari Vositalar Git, Docker, Linux Asoslar Algoritmlar, SQL, tarmoqlar
Python bilan borishingiz mumkin bo'lgan yo'nalishlar
Eng muhim maslahat

Darslik o'qish - bu boshlanishi. Haqiqiy o'rganish o'z loyihangizni yozganingizda boshlanadi.

Kichik boshlang: telefon kitobi, ob-havo boti, fayllarni saralovchi skript. Har bir loyihada yangi narsa duch keladi va aynan shu paytda bilim mustahkamlanadi. Kod yozmasdan o'qilgan 100 ta darslik - yozilgan 1 ta loyihadan kamroq foyda beradi.

Yakuniy xulosa #

Siz 20 ta bo'limda quyidagilarni o'rgandingiz:

  • Python sintaksisi, ma'lumot turlari va operatorlar
  • Ro'yxat, kortej, lug'at va to'plamlar bilan ishlash
  • Shartlar, sikllar va funksiyalar
  • Modullar, paketlar va virtual muhit
  • Fayllar, CSV va JSON formatlari
  • Xatoliklarni professional boshqarish
  • Obyektga yo'naltirilgan dasturlashning barcha tamoyillari
  • Generatorlar, dekoratorlar va kontekst menejerlar
  • Standart kutubxonaning eng kerakli modullari
  • Ma'lumotlar bazasi, API va testlar

Bu - boshlang'ich dasturchi uchun to'liq bilimlar to'plami. Endi siz haqiqiy loyihalar yozishga tayyorsiz.

Omad tilaymiz! Savol yoki taklifingiz bo'lsa, har bir sahifa pastidagi tugma orqali bizga yozing.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.