Xatolar bilan ishlash: try / except
Bu bobda
- traceback ni o'qishni
try/exceptbilan xatoni ushlab, dasturni yiqilishdan saqlashnielsevafinallyqachon kerakligini- bir nechta xato turini alohida ushlashni
- o'z funksiyangizda
raisebilan xato berishni
Xato — bu xabar
Shu paytgacha xato chiqsa, dastur to'xtardi. Python xatolarni istisno (exception) deb ataydi va ular haqida batafsil xabar beradi. Jupyterda u shunday ko'rinadi:
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Cell In[3], line 2
1 a = 10
----> 2 print(a / 0)
ZeroDivisionError: division by zero
Bu traceback. Uni pastdan yuqoriga o'qing:
- Oxirgi qator — xato turi va sababi:
ZeroDivisionError: division by zero. - Strelka
---->— qaysi qatorda yuz berdi: 2-qator. - Funksiyalar ichida bo'lsa, yuqorida chaqiruvlar zanjiri ko'rinadi.
Kitob davomida uchratgan xatolarimiz:
| Xato | Qachon | Bob |
|---|---|---|
SyntaxError |
yozuv qoidasi buzilgan (: yo'q, = o'rniga ==) |
1, 6 |
IndentationError |
chekinish noto'g'ri | 6 |
NameError |
bunday nom yo'q | 1 |
TypeError |
tur mos emas: "20" + 1 |
2 |
ValueError |
qiymat noto'g'ri: int("abc") |
2 |
ZeroDivisionError |
nolga bo'lish | 3 |
IndexError |
indeks chegaradan tashqari | 5, 9 |
KeyError |
lug'atda bunday kalit yo'q | 11 |
AttributeError |
obyektda bunday atribut yo'q | 17 |
FileNotFoundError |
fayl topilmadi | 19 |
Ba'zi xatolar — dasturchi xatosi (SyntaxError, NameError): ularni kodni tuzatib yo'qotasiz. Boshqalari — tashqi dunyo xatosi: foydalanuvchi harf kiritdi, fayl yo'q, internet uzildi. Bularni oldindan bilib bo'lmaydi — ularni ushlash kerak.
try / except
try: print(5 / 0) except ZeroDivisionError: print("Nolga bo'lib bo'lmaydi!") print("Dastur davom etmoqda")
Nolga bo'lib bo'lmaydi! Dastur davom etmoqda
try:ichidagi kod sinab ko'riladi.- Xato chiqsa, Python
tryning qolgan qismini tashlab, mosexceptga o'tadi. - Xato ushlangani uchun dastur yiqilmadi va davom etdi.
Foydalanuvchi kiritishini himoyalash
Bo'lish kalkulyatori. Birinchi variant int() dagi xatoni hisobga olmaydi:
print("Ikki son kiriting, bo'lib beraman. Chiqish uchun 'q'.") while True: birinchi = input("Birinchi son: ") if birinchi == "q": break ikkinchi = input("Ikkinchi son: ") if ikkinchi == "q": break try: javob = int(birinchi) / int(ikkinchi) except ZeroDivisionError: print("Nolga bo'lib bo'lmaydi!") else: print(javob)
Ikki son kiriting, bo'lib beraman. Chiqish uchun 'q'. Birinchi son: 12 Ikkinchi son: 0 Nolga bo'lib bo'lmaydi! Birinchi son: 8 Ikkinchi son: abc
ValueError: invalid literal for int() with base 10: 'abc'
Nolni ushladik, lekin abc kiritilganda int() ValueError berdi va dastur yiqildi. Ikkala xatoni ham ushlaymiz:
print("Ikki son kiriting, bo'lib beraman. Chiqish uchun 'q'.") while True: birinchi = input("Birinchi son: ") if birinchi == "q": break ikkinchi = input("Ikkinchi son: ") if ikkinchi == "q": break try: javob = int(birinchi) / int(ikkinchi) except ZeroDivisionError: print("Nolga bo'lib bo'lmaydi!") except ValueError: print("Faqat butun son kiriting!") else: print(javob)
Ikki son kiriting, bo'lib beraman. Chiqish uchun 'q'. Birinchi son: 12 Ikkinchi son: 0 Nolga bo'lib bo'lmaydi! Birinchi son: 8 Ikkinchi son: abc Faqat butun son kiriting! Birinchi son: 9 Ikkinchi son: 3 3.0 Birinchi son: q
Har bir except o'z xato turini ushlaydi. Endi dasturni hech qanday kiritish bilan yiqitib bo'lmaydi.
else va finally
To'liq tuzilma:
try: # xato berishi mumkin bo'lgan kod except XatoTuri: # xato bo'lganda else: # xato BO'LMAGANDA finally: # har doim, xato bo'lsa ham, bo'lmasa ham
else— faqattrymuvaffaqiyatli o'tganda. Xato bermaydigan kodnitryichiga tiqmaslik uchun ishlatiladi:tryimkon qadar qisqa bo'lsin.finally— tozalash uchun: faylni yopish, ulanishni uzish, "tugadi" deb yozish.
def bol(a, b): try: natija = a / b except ZeroDivisionError: print(f"{a} / {b}: nolga bo'lish") return None else: print(f"{a} / {b} = {natija}") return natija finally: print(" (bol() tugadi)") bol(10, 4) bol(1, 0)
10 / 4 = 2.5 (bol() tugadi) 1 / 0: nolga bo'lish (bol() tugadi)
finally hatto return dan keyin ham bajarildi.
Xato haqida ma'lumot olish: as e
qiymatlar = ["12", "3.5", "abc", ""] for q in qiymatlar: try: print(int(q)) except ValueError as e: print(f"{q!r} -> xato: {e}")
12 '3.5' -> xato: invalid literal for int() with base 10: '3.5' 'abc' -> xato: invalid literal for int() with base 10: 'abc' '' -> xato: invalid literal for int() with base 10: ''
as e — xato obyektini e ga bog'laydi; str(e) — Python bergan xabar.
Fayl topilmasa
fayl = "alisa.txt" try: with open(fayl, encoding="utf-8") as f: matn = f.read() except FileNotFoundError: print(f"Kechirasiz, {fayl} fayli topilmadi.") else: print(len(matn.split()), "so'z")
Kechirasiz, alisa.txt fayli topilmadi.
Bir nechta faylni ko'rib chiqishda — yo'g'ini o'tkazib yuborib davom etish:
from pathlib import Path Path("bir.txt").write_text("olma anor behi", encoding="utf-8") Path("uch.txt").write_text("bir ikki", encoding="utf-8") for nom in ["bir.txt", "ikki.txt", "uch.txt"]: try: with open(nom, encoding="utf-8") as f: soni = len(f.read().split()) except FileNotFoundError: continue print(f"{nom}: {soni} so'z")
bir.txt: 3 so'z uch.txt: 2 so'z
Xato haqida xabar ham kerak bo'lmasa, except ichiga pass yoziladi ("hech narsa qilma"). Lekin buni ehtiyot bilan ishlating: jimgina yutilgan xato keyin topilishi eng qiyin xatoga aylanadi.
Hamma xatoni ko'r-ko'rona ushlash
def ortacha(royxat): try: return sum(royxat) / len(royxt) except Exception: return 0 print(ortacha([4, 5, 5]))
0
Javob 0 — noto'g'ri, lekin xato ham yo'q! len(royxt) dagi yozuv xatosi (NameError) except Exception ga tushib, yashirinib qoldi. Qoida: faqat kutgan xatoingizni ushlang — except ZeroDivisionError:, except ValueError:. except: yoki except Exception: faqat o'ylab, xabarni chiqarib yoki yozib qo'yib ishlatiladi.
raise: o'zingiz xato berish
O'z funksiyangiz noto'g'ri qiymat olsa, jim natija qaytarishdan ko'ra xato berish yaxshiroq. 18-bobda @property setter ida shuni qildik:
def yosh_tekshir(yosh): if not isinstance(yosh, int): raise TypeError("Yosh butun son bo'lishi kerak") if not 0 < yosh < 120: raise ValueError(f"Yosh 1 dan 119 gacha bo'lishi kerak, berildi: {yosh}") return yosh for qiymat in [25, -3, "20"]: try: print("To'g'ri:", yosh_tekshir(qiymat)) except (TypeError, ValueError) as e: print(f"{type(e).__name__}: {e}")
To'g'ri: 25 ValueError: Yosh 1 dan 119 gacha bo'lishi kerak, berildi: -3 TypeError: Yosh butun son bo'lishi kerak
except (TypeError, ValueError) — kortej bilan bir nechta turni bitta except da ushlash.
Loyiha: to'g'ri son olguncha so'rash
8-bobda isdigit() bilan qilgan edik, lekin u manfiy va kasr sonlarni tanimaydi. try bilan hammasi to'g'ri ishlaydi:
def son_sora(savol): while True: matn = input(savol) try: return float(matn) except ValueError: print(f"'{matn}' — son emas, qaytadan kiriting.") harorat = son_sora("Harorat: ") print("Qabul qilindi:", harorat)
Harorat: o'n 'o'n' — son emas, qaytadan kiriting. Harorat: -7.5 Qabul qilindi: -7.5
Bu funksiyani endi istalgan dasturda ishlatish mumkin — 22-bobdagi loyihada aynan shunday qilamiz.
Kitoblarda
- Python asoslari: istisnolar bilan ishlash 92–93-betlar.
- Python Crash Course: 10-bob, Exceptions 194–202-betlar (
ZeroDivisionError, Using try-except Blocks, The else Block, Handling the FileNotFoundError Exception, Failing Silently).
Xulosa
- Traceback ni pastdan o'qing: oxirgi qator — xato turi va sababi.
try:→except Tur:→else:(xato bo'lmasa) →finally:(har doim).- Faqat kutgan xatoingizni ushlang;
except Exception:haqiqiy xatolarni yashiradi. except ValueError as e:— xabarni olish;except (A, B):— bir nechta tur.raise ValueError("...")— o'z funksiyangizda noto'g'ri qiymatni rad etish.
Mashqlar
Ikki qatorda ikki qiymat berilgan. Birinchisini ikkinchisiga bo'lib natijani chiqaring. Nolga bo'lishda — Nolga bo'lib bo'lmaydi, son bo'lmasa — Son kiriting.
| Kirish | Kutilgan natija |
|---|---|
| 10, 4 | 2.5 |
| 7, 0 | Nolga bo'lib bo'lmaydi |
| 7, abc | Son kiriting |
Yechimni ko'rish
try: print(float(input()) / float(input())) except ZeroDivisionError: print("Nolga bo'lib bo'lmaydi") except ValueError: print("Son kiriting")
Bitta qatorda qiymatlar berilgan. Ulardan son bo'lganlarining yig'indisini chiqaring (kasr ham bo'lishi mumkin); son bo'lmaganlarini o'tkazib yuboring.
| Kirish | Kutilgan natija |
|---|---|
| 5 abc 2.5 -1 x | 6.5 |
| olma anor | 0 |
| 10 | 10 |
Yechimni ko'rish
s = 0 for q in input().split(): try: s += float(q) except ValueError: pass print(s)
Ro'yxat [10, 20, 30, 40, 50] va indeks berilgan. Shu indeksdagi elementni chiqaring. Indeks chegaradan tashqari bo'lsa — Bunday indeks yo'q, son bo'lmasa — Indeks son bo'lishi kerak.
| Kirish | Kutilgan natija |
|---|---|
| 2 | 30 |
| -1 | 50 |
| 9 | Bunday indeks yo'q |
Yechimni ko'rish
r = [10, 20, 30, 40, 50] try: print(r[int(input())]) except IndexError: print("Bunday indeks yo'q") except ValueError: print("Indeks son bo'lishi kerak")
kvadrat_ildiz(x) funksiyasini yozing: x manfiy bo'lsa ValueError("Manfiy sondan ildiz yo'q") beradi, aks holda x ** 0.5 qaytaradi. Son berilgan; natijani yoki xato xabarini chiqaring.
| Kirish | Kutilgan natija |
|---|---|
| 16 | 4 |
| 2 | 1.4142135623730951 |
| -9 | Manfiy sondan ildiz yo'q |
Yechimni ko'rish
def kvadrat_ildiz(x): if x < 0: raise ValueError("Manfiy sondan ildiz yo'q") return x ** 0.5 try: print(kvadrat_ildiz(float(input()))) except ValueError as e: print(e)
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.