Xato — dasturçining doimiy hamrohi
Har qanday dasturçi, hatto eng tajribalisi ham, har kuni xatolarga duç keladi. Muhimi — xatodan qörqmaslik, balki uni öqiy oliş va dasturni xatolarga çidamli qilib yoziş. Bu bobda aynan şuni örganamiz.
Pythonda xatolar ikki katta guruhga bölinadi:
- Sintaksis xatolari (
SyntaxError) — kod Python qoidalariga mos yozilmagan. Bunday dastur umuman işga tuşmaydi. - Istisnolar (
exception) — kod töğri yozilgan, lekin işlaş paytida kutilmagan holat yuz berdi: nolga böliş, mavjud bölmagan fayl, notöğri maʼlumot va hokazo.
Sintaksis xatolari
Sintaksis xatosi — bu xuddi gapdagi imlo xatosiga öxşaydi. Python kodni bajarişdan oldin uni "öqib çiqadi" va qoidaga zid joyni topsa, birorta qatorni ham bajarmaydi.
print("Salom"
File "salom.py", line 1
print("Salom"
^
SyntaxError: '(' was never closed
if True
print(1)
File "şart.py", line 1
if True
^
SyntaxError: expected ':'
Python 3.12 xabarlari ança tuşunarli: '(' was never closed — qavs yopilmagan, expected ':' — ikki nuqta kutilgan edi. ^ belgisi esa muammo joyini körsatadi. Sintaksis xatolarini try bilan "uşlab" bölmaydi — ularni faqat kodni tuzatib yöqotasiz.
Istisnolar va traceback
Endi sintaktik jihatdan töğri, lekin işlaş paytida "qulaydigan" dasturni köraylik. narx.py fayli:
def ortacha_narx(narxlar):
return sum(narxlar) / len(narxlar)
def hisobot(dokon, narxlar):
print(f"{dokon}: {ortacha_narx(narxlar)} söm")
hisobot("Çorsu bozori", [12000, 15000, 13500])
hisobot("Yangi dökon", [])
Işga tuşirsak:
Çorsu bozori: 13500.0 söm
Traceback (most recent call last):
File "narx.py", line 10, in <module>
hisobot("Yangi dökon", [])
File "narx.py", line 6, in hisobot
print(f"{dokon}: {ortaça_narx(narxlar)} söm")
^^^^^^^^^^^^^^^^^^^^^
File "narx.py", line 2, in ortaça_narx
return sum(narxlar) / len(narxlar)
~~~~~~~~~~~~~^~~~~~~~~~~~~~
ZeroDivisionError: division by zero
Bu matn traceback (yaʼni "orqaga iz") deb ataladi. Uni qörqmasdan öqişni örganing:
- Eng pastki qatordan boşlang. U yerda istisno turi (
ZeroDivisionError) va qisqa izoh (division by zero— nolga böliş) yozilgan. - Yuqoriga qarab çiqing. Har bir
File ..., line ...qatori çaqiruvlar zanjirini körsatadi: 10-qatordagihisobot()→ 6-qatordagiortacha_narx()→ 2-qatordagi böliş amali. - Eng oxirgi
Fileqatori xato aynan qayerda yuz berganini bildiradi. Bizda — böş röyxat uzunligi0ga bölinmoqda.
Eʼtibor bering: birinçi hisobot muvaffaqiyatli bajarildi, ikkinçisi esa dasturni töxtatdi. Istisno uşlanmasa, dastur öşa joyda tugaydi.
Köp uçraydigan istisnolar
| Istisno | Qaçon yuz beradi | Misol |
|---|---|---|
ValueError | Turi töğri, lekin qiymati yaroqsiz | int("beş") |
TypeError | Amal bu turdagi qiymatga mos emas | "5" + 3 |
ZeroDivisionError | Nolga böliş | 10 / 0 |
KeyError | Luğatda bunday kalit yöq | {"a": 1}["b"] |
IndexError | Röyxat çegarasidan taşqariga çiqiş | [1, 2][5] |
FileNotFoundError | Fayl topilmadi | open("yoq.txt") |
AttributeError | Obyektda bunday atribut yoki metod yöq | "matn".push() |
NameError | Özgaruvçi eʼlon qilinmagan | print(nomalum) |
Har birini öz közimiz bilan köraylik. Quyidagi kod har bir xatoni uşlab, uning turi va xabarini çiqaradi (try ni birozdan keyin batafsil tuşuntiramiz):
sinovlar = [
lambda: int("beş"),
lambda: "5" + 3,
lambda: 10 / 0,
lambda: {"olma": 8000}["anor"],
lambda: [1, 2, 3][5],
lambda: open("mavjud_emas.txt"),
]
for sinov in sinovlar:
try:
sinov()
except Exception as xato:
print(f"{type(xato).__name__}: {xato}")
Natija:
ValueError: invalid literal for int() with base 10: 'beş'
TypeError: can only concatenate str (not "int") to str
ZeroDivisionError: division by zero
KeyError: 'anor'
IndexError: list index out of range
FileNotFoundError: [Errno 2] No such file or directory: 'mavjud_emas.txt'
try va except
Istisnoni uşlab, dasturni töxtatmasdan davom ettiriş uçun try ... except işlatiladi:
tryblokiga xato berişi mumkin bölgan kod yoziladi.exceptblokiga xato yuz berganda nima qiliş kerakligi yoziladi.
matn = "yigirma"
try:
yosh = int(matn)
print("Yoşingiz:", yosh)
except ValueError:
print(f"'{matn}' — son emas. Iltimos, raqamlar bilan yozing.")
print("Dastur davom etmoqda...")
Natija:
'yigirma' — son emas. Iltimos, raqamlar bilan yozing.
Dastur davom etmoqda...
int(matn) xato bergan zahoti Python try blokining qolgan qismini taşlab, töğridan-töğri except ga ötadi. print("Yoşingiz:", ...) qatori bajarilmaydi.
Bir neçta except
Bitta try blokidan turli xatolar kelişi mumkin. Har biri uçun alohida except yozasiz — Python ularni yuqoridan pastga tekşiradi va birinçi mos kelganini bajaradi.
narxlar = {"non": 4000, "sut": 12000, "tuxum": 1500}
def jami_narx(mahsulot, miqdor):
try:
jami = narxlar[mahsulot] * int(miqdor)
print(f"{miqdor} ta {mahsulot}: {jami} söm")
except KeyError:
print(f"Keçirasiz, dökonda '{mahsulot}' yöq.")
except ValueError:
print(f"Miqdor notöğri: '{miqdor}'")
jami_narx("non", "3")
jami_narx("asal", "1")
jami_narx("sut", "ikki")
Natija:
3 ta non: 12000 söm
Keçirasiz, dökonda 'asal' yöq.
Miqdor notöğri: 'ikki'
Agar bir neça xatoga bir xil munosabat bildirmoqçi bölsangiz, ularni qavs içida birlaştiring: except (KeyError, ValueError):.
except ... as e — xato haqida maʼlumot oliş
as yordamida istisno obyektini özgaruvçiga oliş mumkin. Unda xato xabari saqlanadi.
qiymatlar = ["12", "3.5", "", "7"]
for q in qiymatlar:
try:
print(int(q) * 2)
except ValueError as e:
print("Xato:", e)
Natija:
24
Xato: invalid literal for int() with base 10: '3.5'
Xato: invalid literal for int() with base 10: ''
14
else va finally
try konstruksiyasining yana ikki ixtiyoriy qismi bor:
else— xato bölmagandagina bajariladi. Xato berişi mumkin bölmagan, lekin muvaffaqiyatga boğliq kodni şu yerga yoziştryblokini qisqa va aniq qiladi.finally— har doim bajariladi: xato bölsa ham, bölmasa ham, hattoreturnbölsa ham. Odatda resurslarni yopiş yoki yakuniy xabar uçun işlatiladi.
def boluvchi(a, b):
print(f"--- {a} / {b} ---")
try:
natija = a / b
except ZeroDivisionError:
print("Nolga bölib bölmaydi!")
else:
print("Javob:", natija)
finally:
print("Hisob yakunlandi.")
boluvchi(10, 4)
boluvchi(7, 0)
Natija:
--- 10 / 4 ---
Javob: 2.5
Hisob yakunlandi.
--- 7 / 0 ---
Nolga bölib bölmaydi!
Hisob yakunlandi.
Töliq tartib quyidagiça: try → (xato bölsa) except yoki (xato bölmasa) else → har doim finally.
raise — istisnoni özingiz qözğatiş
Baʼzan Python nuqtai nazaridan hammasi joyida, lekin sizning dasturingiz mantiği uçun qiymat yaroqsiz böladi. Masalan, yoş manfiy bölişi mumkin emas. Bunday holda raise bilan istisnoni özingiz "otasiz".
def yosh_belgila(yosh: int) -> int:
if not isinstance(yosh, int):
raise TypeError("Yoş butun son bölişi kerak")
if yosh < 0 or yosh > 150:
raise ValueError(f"Yoş 0 va 150 oraliğida bölişi kerak, siz {yosh} berdingiz")
return yosh
for qiymat in [25, -3, "ön"]:
try:
print("Qabul qilindi:", yosh_belgila(qiymat))
except (TypeError, ValueError) as e:
print("Rad etildi:", e)
Natija:
Qabul qilindi: 25
Rad etildi: Yoş 0 va 150 oraliğida bölişi kerak, siz -3 berdingiz
Rad etildi: Yoş butun son bölişi kerak
except içida yozilgan yolğiz raise esa uşlangan xatoni qayta yuqoriga uzatadi. Bu xatoni qayd qilib (masalan, jurnalga yozib), lekin uni yaşirmaslik kerak bölganda foydali.
Öz istisno sinflaringiz
Katta dasturlarda standart istisnolar yetmay qoladi. Exception sinfidan meros olib, öz istisnoingizni yaratiş mumkin. (Sinflar va meros haqida 16-bobda batafsil gaplaşamiz — hozirça şablonni eslab qoliş kifoya.)
class MablagYetarliEmas(Exception):
"""Hisobda pul yetmaganda qözğatiladi."""
def __init__(self, balans, sorov):
self.balans = balans
self.sorov = sorov
super().__init__(f"Balans {balans} söm, lekin {sorov} söm söraldi")
def pul_yechish(balans, summa):
if summa > balans:
raise MablagYetarliEmas(balans, summa)
return balans - summa
balans = 150_000
for summa in [50_000, 200_000]:
try:
balans = pul_yechish(balans, summa)
print(f"{summa} söm yeçildi. Qoldiq: {balans}")
except MablagYetarliEmas as e:
print("Amal bajarilmadi:", e)
print("Yetişmayotgan summa:", e.sorov - e.balans)
Natija:
50000 söm yeçildi. Qoldiq: 100000
Amal bajarilmadi: Balans 100000 söm, lekin 200000 söm söraldi
Yetişmayotgan summa: 100000
Öz istisnoingizning afzalligi — uni boşqa xatolardan aniq ajratib uşlaş mumkin va unga qöşimça maʼlumot (bu yerda balans va sorov) biriktiriladi.
Amaliyot: xavfsiz böliş
Keling, heç qaçon "qulamaydigan" böliş funksiyasini yozamiz. U har qanday kiritişni qabul qiladi va natija yoki tuşunarli xabar qaytaradi.
def xavfsiz_bolish(a, b):
try:
return float(a) / float(b)
except ZeroDivisionError:
return "Xato: nolga bölib bölmaydi"
except (ValueError, TypeError):
return f"Xato: {a!r} yoki {b!r} son emas"
misollar = [(10, 4), ("15", "3"), (8, 0), ("on", 2), (None, 5)]
for a, b in misollar:
print(f"{a!r} / {b!r} → {xavfsiz_bolish(a, b)}")
Natija:
10 / 4 → 2.5
'15' / '3' → 5.0
8 / 0 → Xato: nolga bölib bölmaydi
'on' / 2 → Xato: 'on' yoki 2 son emas
None / 5 → Xato: None yoki 5 son emas
Amaliyot: işonçli kiritiş öquvçisi
Foydalanuvçi har doim ham töğri maʼlumot kiritmaydi: harf yozib yuboradi, manfiy son beradi, böş qoldiradi. Şuning uçun kiritişni tsikl içida tekşiriş odat tusiga kirgan: töğri qiymat kelmagunça qayta söraymiz.
Funksiyamiz kiritiş funksiyasini parametr sifatida oladi. Odatda bu input, lekin sinov uçun örniga oldindan tayyorlangan javoblarni bera olamiz.
def son_oqi(savol, eng_kichik=None, eng_katta=None, kiritish=input):
while True:
matn = kiritish(savol).strip()
try:
son = int(matn)
except ValueError:
print(" ✗ Butun son kiriting.")
continue
if eng_kichik is not None and son < eng_kichik:
print(f" ✗ Son {eng_kichik} dan kiçik bölmasin.")
elif eng_katta is not None and son > eng_katta:
print(f" ✗ Son {eng_katta} dan katta bölmasin.")
else:
return son
# Sinov: foydalanuvçi ketma-ket şu javoblarni yozdi deb faraz qilamiz
javoblar = iter(["ön sakkiz", "-4", "250", "19"])
def soxta_kiritish(savol):
javob = next(javoblar)
print(savol + javob)
return javob
yosh = son_oqi("Yoşingiz: ", 0, 120, kiritish=soxta_kiritish)
print("Qabul qilindi:", yosh)
Natija:
Yoşingiz: ön sakkiz
✗ Butun son kiriting.
Yoşingiz: -4
✗ Son 0 dan kiçik bölmasin.
Yoşingiz: 250
✗ Son 120 dan katta bölmasin.
Yoşingiz: 19
Qabul qilindi: 19
Haqiqiy dasturda şunçaki yosh = son_oqi("Yoşingiz: ", 0, 120) deb çaqirasiz va funksiya oddiy input() bilan işlaydi.
Xatolarni jamlab hisobot beriş
Köpinça bitta xato tufayli butun işni töxtatiş şart emas. Masalan, talabalar baholari matn körinişida keldi va ularning baʼzilari buzilgan. Yaroqlilarini hisoblab, yaroqsizlari haqida xabar beramiz:
qatorlar = ["Aziza:95", "Bekzod:87", "Gulnoz:", "Doniyor:yuz", "Erkin:72", "Feruza"]
baholar = {}
xatolar = []
for qator in qatorlar:
try:
ism, baho = qator.split(":")
baholar[ism] = int(baho)
except ValueError as e:
xatolar.append(f"'{qator}' — {e}")
print("Yaroqli baholar:", baholar)
print(f"Örtaça: {sum(baholar.values()) / len(baholar):.1f}")
print("Ötkazib yuborilgan qatorlar:")
for x in xatolar:
print(" -", x)
Natija:
Yaroqli baholar: {'Aziza': 95, 'Bekzod': 87, 'Erkin': 72}
Örtaça: 84.7
Ötkazib yuborilgan qatorlar:
- 'Gulnoz:' — invalid literal for int() with base 10: ''
- 'Doniyor:yuz' — invalid literal for int() with base 10: 'yuz'
- 'Feruza' — not enough values to unpack (expected 2, got 1)
Xulosa
- Sintaksis xatosi dasturni umuman işga tuşirmaydi; istisno esa işlaş paytida yuz beradi.
tracebackni pastdan yuqoriga öqing: oxirgi qator — xato turi, undan yuqoridagilar — çaqiruvlar zanjiri.try/exceptistisnoni uşlaydi; iloji boriça aniq turini yozing (ValueError,KeyError...).except ... as exato xabarini beradi,elsefaqat muvaffaqiyatda,finallyhar doim bajariladi.raisebilan özingiz istisno qözğatasiz;Exceptiondan meros olib, öz istisno sinfingizni yaratasiz.- Foydalanuvçi kiritişini tsikl içida tekşirib, töğri qiymat kelgunça qayta sörang.
Maşqlar
royxatdan_ol(royxat, indeks)funksiyasini yozing: element mavjud bölsa uni, aks holda"Bunday indeks yöq"matnini qaytarsin.[10, 20, 30]röyxati uçun1va7indekslarini sinang.
Yeçim
def royxatdan_ol(royxat, indeks):
try:
return royxat[indeks]
except IndexError:
return "Bunday indeks yöq"
sonlar = [10, 20, 30]
print(royxatdan_ol(sonlar, 1))
print(royxatdan_ol(sonlar, 7))
["5", "12", "abc", "0", "7.5", "3"]röyxatidagi har bir qiymatniintga aylantirib,100ni unga böling. Har bir holat uçun natija yoki xato turini çiqaring.
Yeçim
for q in ["5", "12", "abc", "0", "7.5", "3"]:
try:
print(q, "→", 100 / int(q))
except ZeroDivisionError:
print(q, "→ nolga böliş")
except ValueError:
print(q, "→ butun son emas")
harorat_tekshir(gradus)funksiyasini yozing: agar harorat-90dan past yoki60dan yuqori bölsa (Yerda bunday ob-havo deyarli bölmaydi),ValueErrorqözğatsin.25,-120,70qiymatlari bilan sinang.
Yeçim
def harorat_tekshir(gradus):
if not -90 <= gradus <= 60:
raise ValueError(f"{gradus}°C — işonib bölmaydigan harorat")
return gradus
for g in [25, -120, 70]:
try:
print("Töğri:", harorat_tekshir(g))
except ValueError as e:
print("Xato:", e)
ParolZaifnomli öz istisno sinfingizni yarating.parol_tekshir(parol)funksiyasi parol 8 belgidan qisqa bölsa yoki unda raqam bölmasaParolZaifqözğatsin."salom","salomdunyo","salom2025"bilan sinang.
Yeçim
class ParolZaif(Exception):
pass
def parol_tekshir(parol):
if len(parol) < 8:
raise ParolZaif("kamida 8 belgi bölişi kerak")
if not any(b.isdigit() for b in parol):
raise ParolZaif("kamida bitta raqam bölişi kerak")
return True
for p in ["salom", "salomdunyo", "salom2025"]:
try:
parol_tekshir(p)
print(p, "— yaxşi parol")
except ParolZaif as e:
print(p, "— zaif:", e)
finallyqaçon bajarilişini tekşiring: funksiya içidatryblokidanreturnqilinsa hamfinallyişlaşini körsatadigan kiçik misol yozing.
Yeçim
def sinov():
try:
print("try içida")
return "qaytarilgan qiymat"
finally:
print("finally baribir işladi")
print(sinov())