Yakuniy loyiha: talabalar jurnali
Bu bobda
- kitobdagi hamma mavzuni bitta ishlaydigan dasturda birlashtirishni
- dasturni modul, klass va funksiyalarga bo'lishni
- ma'lumotni JSON da saqlab, hisobotni txt ga chiqarishni
- foydalanuvchi bilan menyu orqali muloqot qilishni
- dasturni bosqichma-bosqich sinab ko'rishni
Vazifa
O'qituvchi uchun kichik dastur kerak:
- Talaba qo'shish (ism, guruh).
- Talabaga fan bo'yicha baho qo'yish (2–5).
- Har bir talabaning o'rtacha bahosi va guruh reytingi.
- Ma'lumot dastur yopilganda yo'qolmasin — JSON faylda saqlansin.
- Reytingni chiroyli txt hisobot qilib chiqarish.
- Noto'g'ri kiritish (harf, 7 baho, yo'q talaba) dasturni yiqitmasin.
Qaysi bobdan nima kerak bo'ladi:
| Qism | Nima ishlatamiz | Bob |
|---|---|---|
| Talaba ma'lumoti | @dataclass, ro'yxat, lug'at |
9, 11, 18 |
| Jurnal | klass, metodlar, @property |
16, 18 |
| Saqlash | JSON, asdict, ** |
14, 21 |
| Hisobot | txt fayl, f-string tekislash | 5, 19 |
| Tekshiruv | raise, try/except |
20 |
| Menyu | while True, if/elif, funksiyalar |
6, 8, 13 |
| Tuzilma | alohida modul | 15 |
1-qadam: model — jurnal.py
Butun "biznes mantiq" bitta modulda. Menyu (foydalanuvchi bilan gaplashish) undan alohida bo'ladi: shunda bir xil modulni keyin Telegram bot yoki veb-sayt bilan ham ishlatish mumkin.
Fayl: jurnal.py
"""Talabalar jurnali: talabalar, baholar, JSON ga saqlash va txt hisobot.""" import json from dataclasses import asdict, dataclass, field from pathlib import Path BAHOLAR = (2, 3, 4, 5) @dataclass class Talaba: ism: str guruh: str baholar: dict = field(default_factory=dict) def baho_qosh(self, fan, baho): if baho not in BAHOLAR: raise ValueError(f"Baho 2 dan 5 gacha bo'lishi kerak, berildi: {baho}") self.baholar.setdefault(fan, []).append(baho) @property def ortacha(self): hammasi = [b for royxat in self.baholar.values() for b in royxat] return sum(hammasi) / len(hammasi) if hammasi else 0.0 class Jurnal: def __init__(self, fayl="jurnal.json"): self.fayl = Path(fayl) self.talabalar = {} self.yukla() def yukla(self): try: royxat = json.loads(self.fayl.read_text(encoding="utf-8")) except FileNotFoundError: return except json.JSONDecodeError: print(f"Ogohlantirish: {self.fayl} buzilgan, bo'sh jurnal ochildi") return self.talabalar = {d["ism"]: Talaba(**d) for d in royxat} def saqla(self): royxat = [asdict(t) for t in self.talabalar.values()] self.fayl.write_text(json.dumps(royxat, ensure_ascii=False, indent=2), encoding="utf-8") def talaba_qosh(self, ism, guruh): ism = ism.strip().title() if not ism: raise ValueError("Ism bo'sh bo'lmasin") if ism in self.talabalar: raise ValueError(f"{ism} allaqachon bor") self.talabalar[ism] = Talaba(ism, guruh.strip().upper()) return self.talabalar[ism] def topish(self, ism): talaba = self.talabalar.get(ism.strip().title()) if talaba is None: raise KeyError(f"{ism} degan talaba yo'q") return talaba def reyting(self, guruh=None): royxat = [t for t in self.talabalar.values() if guruh is None or t.guruh == guruh] return sorted(royxat, key=lambda t: t.ortacha, reverse=True) def hisobot(self, fayl="hisobot.txt"): sarlavha = "#".ljust(3) + "Talaba".ljust(20) + "Guruh".ljust(7) + "Baho".rjust(6) + "O'rtacha".rjust(10) qatorlar = [sarlavha, "-" * len(sarlavha)] for i, t in enumerate(self.reyting(), start=1): soni = sum(len(r) for r in t.baholar.values()) qatorlar.append(f"{i:<3}{t.ism:<20}{t.guruh:<7}{soni:>6}{t.ortacha:>10.2f}") matn = "\n".join(qatorlar) + "\n" Path(fayl).write_text(matn, encoding="utf-8") return matn
Bu yerda ikkita yangi narsa bor:
self.baholar.setdefault(fan, [])— lug'atdafanbo'lmasa, uni bo'sh ro'yxat bilan yaratadi va ro'yxatni qaytaradi..append(baho)shu ro'yxatga qo'shadi. Bu 11-bobdagiget(k, 0) + 1andozasining ro'yxatlar uchun varianti.[b for royxat in ... for b in royxat]— ikkiforli comprehension: "har bir fan ro'yxatidagi har bir baho". Ichma-ich siklni bir qatorda yozish."Talaba".ljust(20)— satrni 20 belgigacha o'ngdan probel bilan to'ldiradi,rjust— chapdan. Buf"{x:<20}"ning metod shakli; sarlavhadaO'rtachaso'zidagi apostrof f-string ichida muammo tug'dirmasligi uchun shunday yozdik.
2-qadam: modulni sinab ko'rish
Menyu yozishdan oldin, mantiq to'g'ri ishlashini kod bilan tekshiramiz. Toza boshlash uchun eski faylni o'chiramiz:
from pathlib import Path from jurnal import Jurnal Path("jurnal.json").unlink(missing_ok=True) j = Jurnal() j.talaba_qosh("sarvinoz karimova", "ai-1") j.talaba_qosh("ali valiyev", "ai-1") j.talaba_qosh("otabek", "ai-2") j.topish("Sarvinoz Karimova").baho_qosh("Python", 5) j.topish("sarvinoz karimova").baho_qosh("Matematika", 4) j.topish("Ali Valiyev").baho_qosh("Python", 4) j.topish("Ali Valiyev").baho_qosh("Python", 3) j.topish("Otabek").baho_qosh("Python", 5) for t in j.reyting(): print(f"{t.ism:<18}{t.guruh:<6}{t.ortacha:.2f} {t.baholar}")
Otabek AI-2 5.00 {'Python': [5]}
Sarvinoz Karimova AI-1 4.50 {'Python': [5], 'Matematika': [4]}
Ali Valiyev AI-1 3.50 {'Python': [4, 3]}topish() ismni title() qilib qidiradi, shuning uchun katta-kichik harf muhim emas.
Xatolarni ham sinaymiz — ular dasturni yiqitmasligi, balki tushunarli xabar berishi kerak:
sinovlar = [ lambda: j.talaba_qosh("Otabek", "ai-2"), lambda: j.talaba_qosh(" ", "ai-1"), lambda: j.topish("Javohir"), lambda: j.topish("Otabek").baho_qosh("Python", 7), ] for sinov in sinovlar: try: sinov() except (ValueError, KeyError) as e: print(f"{type(e).__name__}: {e}")
ValueError: Otabek allaqachon bor ValueError: Ism bo'sh bo'lmasin KeyError: "Javohir degan talaba yo'q" ValueError: Baho 2 dan 5 gacha bo'lishi kerak, berildi: 7
Har bir sinovni lambda ichiga o'radik, shunda ular ro'yxat yaratilganda emas, sikl ichida, try ostida chaqiriladi.
3-qadam: saqlash va qayta yuklash
j.saqla() print(Path("jurnal.json").read_text(encoding="utf-8")[:260], "...") yangi = Jurnal() print("Qayta yuklandi:", len(yangi.talabalar), "talaba") print("Sarvinozning o'rtachasi:", yangi.topish("sarvinoz karimova").ortacha)
[
{
"ism": "Sarvinoz Karimova",
"guruh": "AI-1",
"baholar": {
"Python": [
5
],
"Matematika": [
4
]
}
},
{
"ism": "Ali Valiyev",
"guruh": "AI-1",
"baholar": {
"Python": [
4, ...
Qayta yuklandi: 3 talaba
Sarvinozning o'rtachasi: 4.5Jurnal() yangidan yaratildi va ma'lumotni fayldan o'qidi — dastur "eslab qoldi".
Hisobot:
print(yangi.hisobot())
# Talaba Guruh Baho O'rtacha ---------------------------------------------- 1 Otabek AI-2 1 5.00 2 Sarvinoz Karimova AI-1 2 4.50 3 Ali Valiyev AI-1 2 3.50
hisobot.txt fayli ham yaratildi — uni o'qituvchi chop etishi yoki Telegramga yuborishi mumkin.
4-qadam: menyu
Endi foydalanuvchi bilan gaplashadigan qism. U jurnal modulidan foydalanadi va har bir amalni alohida funksiyada bajaradi:
Fayl: dastur.py
from jurnal import Jurnal MENYU = """ 1 - talaba qo'shish 2 - baho qo'yish 3 - reyting 4 - hisobot (txt) 0 - chiqish""" def talaba_qosh(j): j.talaba_qosh(input("Ism familiya: "), input("Guruh: ")) print("Qo'shildi.") def baho_qoy(j): talaba = j.topish(input("Talaba: ")) fan = input("Fan: ").strip().capitalize() matn = input("Baho (2-5): ").strip() if not matn.isdigit(): raise ValueError(f"'{matn}' — son emas") baho = int(matn) talaba.baho_qosh(fan, baho) print(f"{talaba.ism}: {fan} — {baho}") def reyting(j): for i, t in enumerate(j.reyting(), start=1): print(f"{i}. {t.ism} ({t.guruh}) — {t.ortacha:.2f}") def hisobot(j): j.hisobot() print("hisobot.txt yozildi.") AMALLAR = {"1": talaba_qosh, "2": baho_qoy, "3": reyting, "4": hisobot} def main(): j = Jurnal() print(f"Jurnal ochildi: {len(j.talabalar)} talaba.") while True: print(MENYU) tanlov = input("Tanlang: ").strip() if tanlov == "0": j.saqla() print("Saqlandi. Xayr!") break amal = AMALLAR.get(tanlov) if amal is None: print("Bunday band yo'q.") continue try: amal(j) j.saqla() except ValueError as e: print("Xato:", e) except KeyError as e: print("Xato:", e.args[0]) if __name__ == "__main__": main()
E'tibor bering:
AMALLARlug'ati menyu raqamini funksiyaga bog'laydi. Uzunif/elifzanjiri o'rniga — bittaget(). Yangi band qo'shish uchun bitta funksiya va lug'atga bitta qator yetadi.- Xatolar bitta joyda —
main()dagitryda ushlanadi.baho_qoy()baho son emasligini o'zi tekshirib, tushunarli o'zbekchaValueErrorberadi; Pythonning inglizchainvalid literal for int()xabari foydalanuvchiga ko'rinmaydi. - Har bir muvaffaqiyatli amaldan keyin
j.saqla()— dastur kutilmaganda yopilsa ham ma'lumot yo'qolmaydi. e.args[0]—KeyErrorxabarini qo'shtirnoqsiz olish uchun.
Sinab ko'ramiz. Kitobda kiritishlar oldindan berilgan; o'zingizda terminalda python dastur.py yoki Jupyterda %run dastur.py:
import dastur dastur.main()
Jurnal ochildi: 3 talaba. 1 - talaba qo'shish 2 - baho qo'yish 3 - reyting 4 - hisobot (txt) 0 - chiqish Tanlang: 2 Talaba: ali valiyev Fan: matematika Baho (2-5): 5 Ali Valiyev: Matematika — 5 1 - talaba qo'shish 2 - baho qo'yish 3 - reyting 4 - hisobot (txt) 0 - chiqish Tanlang: 2 Talaba: javohir Xato: javohir degan talaba yo'q 1 - talaba qo'shish 2 - baho qo'yish 3 - reyting 4 - hisobot (txt) 0 - chiqish Tanlang: 1 Ism familiya: javohir tursunov Guruh: ai-2 Qo'shildi. 1 - talaba qo'shish 2 - baho qo'yish 3 - reyting 4 - hisobot (txt) 0 - chiqish Tanlang: 2 Talaba: javohir tursunov Fan: python Baho (2-5): besh Xato: 'besh' — son emas 1 - talaba qo'shish 2 - baho qo'yish 3 - reyting 4 - hisobot (txt) 0 - chiqish Tanlang: 2 Talaba: Javohir Tursunov Fan: Python Baho (2-5): 4 Javohir Tursunov: Python — 4 1 - talaba qo'shish 2 - baho qo'yish 3 - reyting 4 - hisobot (txt) 0 - chiqish Tanlang: 9 Bunday band yo'q. 1 - talaba qo'shish 2 - baho qo'yish 3 - reyting 4 - hisobot (txt) 0 - chiqish Tanlang: 3 1. Otabek (AI-2) — 5.00 2. Sarvinoz Karimova (AI-1) — 4.50 3. Ali Valiyev (AI-1) — 4.00 4. Javohir Tursunov (AI-2) — 4.00 1 - talaba qo'shish 2 - baho qo'yish 3 - reyting 4 - hisobot (txt) 0 - chiqish Tanlang: 0 Saqlandi. Xayr!
Jurnal fayldan 3 talaba bilan ochildi; noma'lum talaba, "besh" degan baho va mavjud bo'lmagan band dasturni yiqitmadi; chiqishda hammasi saqlandi.
Oxirgi tekshiruv — dastur qayta ochilganda Javohir va yangi baholar joyidami:
from jurnal import Jurnal j = Jurnal() print(len(j.talabalar), "talaba") print(j.hisobot())
4 talaba # Talaba Guruh Baho O'rtacha ---------------------------------------------- 1 Otabek AI-2 1 5.00 2 Sarvinoz Karimova AI-1 2 4.50 3 Ali Valiyev AI-1 3 4.00 4 Javohir Tursunov AI-2 1 4.00
Loyihani qanday rivojlantirish mumkin
Bu dastur keyingi kurslar uchun asos. Masalan:
- Telegram bot: dastur.py o'rniga bot yozing — jurnal.py o'zgarmaydi.
- Grafik: matplotlib bilan guruhlar o'rtachasini ustunli diagrammada chizing.
- Ma'lumotlar bazasi: JSON o'rniga SQLite (sqlite3 — standart kutubxonada bor).
- Testlar: pytest bilan Talaba va Jurnal metodlarini avtomatik tekshirish — keyingi kitob "Python muhandisligi" shundan boshlanadi.
Xulosa: siz nimalarni o'rgandingiz
| Bo'lim | Mavzular |
|---|---|
| Asoslar (1–5) | o'zgaruvchilar, turlar, arifmetika, math, satrlar |
| Boshqaruv (6–8) | if, for, while, break, continue |
| Tuzilmalar (9–12) | list, tuple, dict, set, comprehension |
| Funksiyalar (13–15) | def, return, *args, lambda, modullar |
| OOP (16–18) | klass, meros, kompozitsiya, maxsus metodlar, @property, dataclass |
| Fayllar (19–21) | txt, try/except, JSON |
| Loyiha (22) | hammasi birga |
Endi siz kichik, lekin haqiqiy dastur yoza olasiz: u ma'lumotni saqlaydi, xatoga chidamli va qismlarga bo'lingan. Sun'iy intellekt muhandisligi yo'lidagi keyingi qadam — numpy, pandas va ma'lumotlar bilan ishlash.
Mashqlar
Bitta qatorda fan:baho juftlari berilgan, masalan python:5 matematika:4 python:3. Har bir fan bo'yicha o'rtacha bahoni, fanlar alifbo tartibida, fan o'rtacha ko'rinishida (2 xona bilan) chiqaring. Maslahat: setdefault(fan, []).append(baho).
| Kirish | Kutilgan natija |
|---|---|
| python:5 matematika:4 python:3 | matematika 4.00 python 4.00 |
| ingliz:5 ingliz:5 ingliz:2 | ingliz 4.00 |
Yechimni ko'rish
fanlar = {} for juft in input().split(): fan, baho = juft.split(":") fanlar.setdefault(fan, []).append(int(baho)) for fan in sorted(fanlar): print(fan, f"{sum(fanlar[fan]) / len(fanlar[fan]):.2f}")
Menyu buyruqlari ketma-ket berilgan (har biri alohida qatorda): qosh <son>, ayir <son>, kor, chiq. Boshlang'ich qiymat 0. kor da joriy qiymatni chiqaring, chiq da to'xtang. Noto'g'ri buyruq yoki son bo'lmasa — Xato chiqaring va davom eting. Buyruqlarni AMALLAR lug'ati bilan bajaring.
| Kirish | Kutilgan natija |
|---|---|
| qosh 5, ayir 2, kor, qosh x, uchir 1, qosh 10, kor, chiq | 3 Xato Xato 13 |
| kor, chiq | 0 |
Yechimni ko'rish
qiymat = 0 def qosh(n): global qiymat qiymat += n def ayir(n): global qiymat qiymat -= n AMALLAR = {"qosh": qosh, "ayir": ayir} while True: buyruq = input().split() if buyruq == ["chiq"]: break if buyruq == ["kor"]: print(qiymat) continue try: AMALLAR[buyruq[0]](int(buyruq[1])) except (KeyError, IndexError, ValueError): print("Xato")
Mustaqil ish (yakuniy topshiriq)
jurnal.py ni kengaytiring va har bir qadamni sinab ko'ring:
Jurnal.talaba_ochir(ism)— talabani o'chirish (yo'q bo'lsaKeyError).Talaba.fan_ortacha(fan)— bitta fan bo'yicha o'rtacha.Jurnal.eng_yaxshi(fan)— shu fan bo'yicha eng yuqori o'rtachali talaba.- Menyuga 5- va 6-bandlarni qo'shing.
- Hisobotga har bir guruh uchun alohida reyting bo'limi qo'shing (
reyting(guruh=...)tayyor). - Bonus: ikkita jurnal faylini birlashtiradigan funksiya yozing (bir xil talaba ikkala faylda bo'lsa, baholarini qo'shing).
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.