Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Pythonning o'z ierarxiyasi
- 2.2. Loyihalash tamoyillari
- 2.3. Ierarxiya antipatternlari
- 2.4. OSError — namunali dizayn
- 2.5. Mashhur kutubxonalar
- 2.6. Migratsiya strategiyalari
- 2.7. Ierarxiyani sinash
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Pythonning o'z ierarxiyasi
- Misol 2 — Ierarxiya loyihalash
- Misol 3 — Migratsiya va orqaga moslik
- Misol 4 — Amaliy: IlmHamroh platformasi ierarxiyasi
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
9.7-dars: Istisnolar ierarxiyasi
9-QISM — XATOLAR VA ISTISNOLAR · 7-dars
1. Kirish va motivatsiya
Bu ikki kutubxona bir xil ishni qiladi. Farqni ko'ring:
Kutubxona A:
try:
a.sorov("/xodimlar")
except A.UlanmadiXato: ...
except A.VaqtTugadi: ...
except A.HTTPXato: ...
except A.JSONXato: ...
except A.SertifikatXato: ... # ⚠️ va yana 12 taYangi versiyada yangi istisno qo'shilsa — kodingiz buziladi.
Kutubxona B:
try:
b.sorov("/xodimlar")
except b.SorovXatosi: # ⭐ HAMMASI
... Farq — ierarxiya. B da barcha istisnolar bitta asosdan meros oladi, shuning uchun:
- Yangi istisno qo'shilsa — mavjud kod ishlashda davom etadi
- Kerak bo'lganda aniqroq ushlash mumkin
- Toifalar orqali guruh ushlash mumkin
Bu darsda:
- Pythonning o'z ierarxiyasi — to'liq daraxt
- Ierarxiya loyihalash tamoyillari
- Chuqurlik vs kenglik
- Mashhur kutubxonalar tahlili
- Migratsiya va orqaga moslik
- Ierarxiyani sinovdan o'tkazish
2. Nazariya — chuqur tushuntirish
2.1. Pythonning o'z ierarxiyasi
BaseException ⭐ hamma narsaning asosi
├── BaseExceptionGroup (3.11+)
├── GeneratorExit ⚠️ oqim boshqaruvi
├── KeyboardInterrupt ⚠️ Ctrl+C
├── SystemExit ⚠️ sys.exit()
└── Exception ⭐ ODATIY xatolar
├── ArithmeticError
│ ├── FloatingPointError
│ ├── OverflowError
│ └── ZeroDivisionError
├── AssertionError
├── AttributeError
├── BufferError
├── EOFError
├── ExceptionGroup (3.11+)
├── ImportError
│ └── ModuleNotFoundError
├── LookupError ⭐ guruh
│ ├── IndexError
│ └── KeyError
├── MemoryError
├── NameError
│ └── UnboundLocalError
├── OSError ⭐ eng katta guruh
│ ├── BlockingIOError
│ ├── ChildProcessError
│ ├── ConnectionError ⭐ ichki guruh
│ │ ├── BrokenPipeError
│ │ ├── ConnectionAbortedError
│ │ ├── ConnectionRefusedError
│ │ └── ConnectionResetError
│ ├── FileExistsError
│ ├── FileNotFoundError
│ ├── InterruptedError
│ ├── IsADirectoryError
│ ├── NotADirectoryError
│ ├── PermissionError
│ ├── ProcessLookupError
│ └── TimeoutError
├── ReferenceError
├── RuntimeError
│ ├── NotImplementedError
│ ├── RecursionError
│ └── PythonFinalizationError (3.13+)
├── StopAsyncIteration
├── StopIteration
├── SyntaxError
│ └── IndentationError
│ └── TabError
├── SystemError
├── TypeError
├── ValueError
│ └── UnicodeError
│ ├── UnicodeDecodeError
│ ├── UnicodeEncodeError
│ └── UnicodeTranslateError
└── Warning ⭐ warnings moduli
├── DeprecationWarning
├── UserWarning
└── ... (11 ta)Dizayn xususiyatlari:
| Xususiyat | Misol |
|---|---|
| Guruhlash | LookupError = IndexError + KeyError |
| Sayoz | Ko'pchilik 2-3 daraja |
| Toifalar | OSError, ArithmeticError |
| Maxsus | Warning alohida shoxda |
2.2. Loyihalash tamoyillari
1. Bitta asos sinf — MAJBURIY
class KutubxonaXatosi(Exception):
"""Barcha xatolar shundan meros."""Foydalanuvchi bitta blok bilan hammasini ushlaydi.
2. Toifalar — foydalanuvchi HAR XIL ish qilsa
class TarmoqXatosi(KutubxonaXatosi): ... # ⭐ qayta urin
class MalumotXatosi(KutubxonaXatosi): ... # ⭐ tuzatAgar bir xil ish qilinsa — toifa kerak emas.
3. Sayoz — 3 darajadan oshmasin
KutubxonaXatosi 1
└── TarmoqXatosi 2
└── VaqtTugadi 3 ⭐ yetadi
└── DNSVaqt 4 ⚠️ ortiqcha4. Kenglik — chuqurlikdan yaxshi
# ⚠️ CHUQUR
Xato → Tarmoq → HTTP → Mijoz → NotFound
# ✅ SAYOZ
Xato → TarmoqXatosi
→ HTTPXatosi (kod atributi bilan)5. Atributlar — sinflardan yaxshi
# ⚠️ 20 ta sinf
class HTTP400(...), HTTP401(...), HTTP403(...), ...
# ✅ 1 ta sinf + atribut
class HTTPXatosi(Exception):
def __init__(self, kod: int, ...): self.kod = kodQoida: foydalanuvchi alohida ushlaydimi? Ha → sinf. Yo'q → atribut.
2.3. Ierarxiya antipatternlari
# ❌ 1. Tekis — asos yo'q
class XatoA(Exception): ...
class XatoB(Exception): ...
# ❌ 2. Juda chuqur
class A(Exception): ...
class B(A): ...
class C(B): ...
class D(C): ...
class E(D): ... # ⚠️ 5 daraja
# ❌ 3. Sinf portlashi
class Xato400(...), Xato401(...) # ⚠️ har kod uchun
# ❌ 4. Mantiqsiz meros
class VaqtTugadi(ValidatsiyaXatosi): ... # ⚠️ aloqasi yo'q
# ❌ 5. Ko'p meros chalkashligi
class X(TarmoqXatosi, MalumotXatosi): ... # ⚠️ qaysi biri?
# ❌ 6. Bo'sh oraliq
class OraliqXato(AsosXato): ... # ⚠️ hech kim ishlatmaydi
class Haqiqiy(OraliqXato): ...2.4. OSError — namunali dizayn
Python 3.3 gacha (PEP 3151):
try:
open("yoq.txt")
except IOError as e:
if e.errno == errno.ENOENT: # ⚠️ errno tekshirish
...
elif e.errno == errno.EACCES:
...Muammolar:
IOError,OSError,WindowsError,EnvironmentError,socket.error,select.error— 6 ta sinf- Har safar
errnotekshirish - Platformaga bog'liq
Python 3.3 dan keyin:
try:
open("yoq.txt")
except FileNotFoundError: # ⭐ aniq
...
except PermissionError: # ⭐ aniq
... Barcha eski nomlar OSError ga taxallus:
IOError is OSError # True
EnvironmentError is OSError # True
socket.error is OSError # True OSError.__new__ sehri:
type(OSError(2, "yo'q")) # FileNotFoundError ⭐
type(OSError(13, "ruxsat")) # PermissionError ⭐ errno ga qarab avtomatik to'g'ri avlod tanlanadi.
2.5. Mashhur kutubxonalar
requests:
RequestException(IOError) ⭐ IOError dan!
├── ConnectionError
│ ├── ConnectTimeout(+Timeout) ⭐ ko'p meros
│ ├── ProxyError
│ └── SSLError
├── HTTPError
├── Timeout
│ └── ReadTimeout
├── TooManyRedirects
├── URLRequired
└── ... (JSONDecodeError, MissingSchema, ...) ConnectTimeout(ConnectionError, Timeout) — ikkalasi bilan ham ushlanadi.
sqlalchemy:
SQLAlchemyError
├── ArgumentError
├── DBAPIError ⭐ drayver xatosini o'raydi
│ ├── InterfaceError
│ ├── DatabaseError
│ │ ├── DataError
│ │ ├── OperationalError
│ │ ├── IntegrityError ⭐ UNIQUE, FOREIGN KEY
│ │ ├── InternalError
│ │ ├── ProgrammingError
│ │ └── NotSupportedError
│ └── StatementError
└── NoResultFound / MultipleResultsFoundDB-API 2.0 (PEP 249) standarti — barcha drayverlar bir xil.
httpx:
HTTPError
├── RequestError
│ ├── TransportError
│ │ ├── TimeoutException
│ │ │ ├── ConnectTimeout
│ │ │ ├── ReadTimeout
│ │ │ ├── WriteTimeout
│ │ │ └── PoolTimeout
│ │ ├── NetworkError
│ │ ├── ProtocolError
│ │ └── ProxyError
│ └── InvalidURL / CookieConflict
└── HTTPStatusError4 daraja — chuqurroq, lekin mantiqiy.
2.6. Migratsiya strategiyalari
Muammo: eski kod except ValueError: yozgan, siz MeningXatom ga o'tmoqchisiz.
Yechim 1 — ko'p meros:
class MeningXatom(KutubxonaXatosi, ValueError):
"""⭐ Ikkalasi ham ishlaydi."""Yechim 2 — bosqichma-bosqich:
# v2.0: yangi qo'shildi, eski ishlaydi
class YangiXato(EskiXato): ... # ⭐ eskidan meros
# v3.0: eskisi deprecated
class EskiXato(YangiXato): # ⭐ teskari
def __init__(self, *a, **kw):
warnings.warn("EskiXato eskirgan", DeprecationWarning)
super().__init__(*a, **kw)
# v4.0: eskisi olib tashlanadiYechim 3 — taxallus:
EskiNom = YangiNom # ⭐ oddiyIerarxiyani O'ZGARTIRISH — buzuvchi o'zgarish:
# v1.0
class VaqtTugadi(KutubxonaXatosi): ...
# v2.0
class VaqtTugadi(TarmoqXatosi): ... # ⭐ QO'SHISH — xavfsiz
# (TarmoqXatosi ⊂ KutubxonaXatosi)
# ❌ XAVFLI:
class VaqtTugadi(Exception): ... # ⚠️ KutubxonaXatosi'dan chiqdiQoida: ierarxiyani faqat kengaytiring (avlod qo'shing), torayting emas.
2.7. Ierarxiyani sinash
def ierarxiya_tekshir(Asos: type) -> list[str]:
"""⭐ Loyihalash muammolarini topadi."""
muammolar = []
def yur(S, chuqurlik=0, yol=()):
avlodlar = S.__subclasses__()
if chuqurlik > 3:
muammolar.append(f"Juda chuqur: {'.'.join(yol)}")
if len(avlodlar) > 12:
muammolar.append(f"Juda ko'p avlod: {S.__name__}")
if not S.__doc__:
muammolar.append(f"Docstring yo'q: {S.__name__}")
if len(avlodlar) == 1:
muammolar.append(f"Bitta avlod: {S.__name__}")
for A in avlodlar:
yur(A, chuqurlik + 1, yol + (A.__name__,))
yur(Asos)
return muammolar3. Tez ma'lumotnoma
Python ierarxiyasi (asosiy)
BaseException
├── SystemExit / KeyboardInterrupt / GeneratorExit
└── Exception
├── LookupError → IndexError, KeyError
├── OSError → FileNotFoundError, PermissionError,
│ ConnectionError → ConnectionResetError, ...
├── ArithmeticError → ZeroDivisionError, OverflowError
├── ValueError → UnicodeError → UnicodeDecodeError
├── RuntimeError → NotImplementedError, RecursionError
├── NameError → UnboundLocalError
├── ImportError → ModuleNotFoundError
├── SyntaxError → IndentationError → TabError
└── Warning → DeprecationWarning, ...Loyihalash qoidalari
1. Bitta asos sinf MAJBURIY
2. Toifalar — har xil ish qilinsa 2-6 ta
3. Chuqurlik ≤ 3 daraja
4. Kenglik > chuqurlik
5. Atribut > yangi sinf ⭐ eng muhim
6. Har sinfda docstringAntipatternlar
Tekis (asos yo'q) ❌
5+ daraja chuqurlik ❌
Har HTTP kod uchun sinf ❌
Mantiqsiz meros ❌
Bo'sh oraliq sinf ❌Migratsiya
Kengaytirish (avlod qo'shish) ✅ xavfsiz
Ko'p meros (eski + yangi) ✅
Taxallus (EskiNom = YangiNom) ✅
DeprecationWarning bilan ✅
Asosni o'zgartirish (torayish) ❌ buzadi4. Batafsil misollar
Misol 1 — Pythonning o'z ierarxiyasi
"""O'rnatilgan istisnolar daraxtini tahlil qilish."""
import builtins
import sys
print("=== 1. To'liq daraxt ===\n")
def daraxt(Sinf: type, chuqurlik: int = 0, oxirgi: bool = True,
prefiks: str = "", maks: int = 3) -> list[str]:
"""⭐ Istisno daraxtini chizadi."""
if chuqurlik == 0:
qatorlar = [Sinf.__name__]
else:
qatorlar = [f"{prefiks}{'└── ' if oxirgi else '├── '}"
f"{Sinf.__name__}"]
if chuqurlik >= maks:
return qatorlar
avlodlar = sorted(
[c for c in Sinf.__subclasses__()
if c.__module__ == "builtins"],
key=lambda c: c.__name__,
)
yangi = prefiks + ("" if chuqurlik == 0
else (" " if oxirgi else "│ "))
for i, A in enumerate(avlodlar):
qatorlar.extend(
daraxt(A, chuqurlik + 1, i == len(avlodlar) - 1,
yangi, maks)
)
return qatorlar
for q in daraxt(BaseException, maks=2):
print(f" {q}")
print("\n\n=== 2. ⭐ Statistika ===\n")
def barcha(Sinf: type) -> set[type]:
natija = {Sinf}
for A in Sinf.__subclasses__():
if A.__module__ == "builtins":
natija |= barcha(A)
return natija
HAMMASI = barcha(BaseException)
print(f" Jami o'rnatilgan istisno: {len(HAMMASI)}")
def chuqurlik(Sinf: type) -> int:
d = 0
for K in Sinf.__mro__:
if K is BaseException:
break
d += 1
return d
darajalar: dict[int, list[str]] = {}
for S in HAMMASI:
darajalar.setdefault(chuqurlik(S), []).append(S.__name__)
print(f"\n {'Daraja':<9} {'Soni':<7} {'Misollar'}")
print(" " + "─" * 66)
for d in sorted(darajalar):
nomlar = sorted(darajalar[d])
print(f" {d:<9} {len(nomlar):<7} "
f"{', '.join(nomlar[:5])}"
f"{' ...' if len(nomlar) > 5 else ''}")
print(f"""
⭐ XULOSA: ko'pchilik istisno 1-3 daraja chuqurlikda.
Eng chuqur: {max(darajalar)} daraja.
""")
print("=== 3. ⭐ Eng ko'p avlodli sinflar ===\n")
def avlodlar_soni(Sinf: type) -> int:
return len(barcha(Sinf)) - 1
ro = sorted(
((S, avlodlar_soni(S)) for S in HAMMASI),
key=lambda p: -p[1],
)
print(f" {'Sinf':<22} {'Avlodlar':<11} {'Bevosita'}")
print(" " + "─" * 50)
for S, n in ro[:10]:
bevosita = len([c for c in S.__subclasses__()
if c.__module__ == "builtins"])
print(f" {S.__name__:<22} {n:<11} {bevosita}")
print("\n\n=== 4. ⭐ OSError oilasi ===\n")
for q in daraxt(OSError, maks=2):
print(f" {q}")
print(f"\n ⭐ Taxalluslar (PEP 3151 dan keyin):\n")
import socket
import select
TAXALLUSLAR = [
("IOError", IOError),
("EnvironmentError", EnvironmentError),
("socket.error", socket.error),
("select.error", select.error),
]
for nom, Sinf in TAXALLUSLAR:
print(f" {nom:<20} is OSError → {Sinf is OSError}")
print(f"\n ⭐ OSError.__new__ sehri (errno → avlod):\n")
import errno
KODLAR = [
(errno.ENOENT, "ENOENT"),
(errno.EACCES, "EACCES"),
(errno.EEXIST, "EEXIST"),
(errno.EISDIR, "EISDIR"),
(errno.ENOTDIR, "ENOTDIR"),
(errno.ECONNREFUSED, "ECONNREFUSED"),
(errno.ECONNRESET, "ECONNRESET"),
(errno.EPIPE, "EPIPE"),
(errno.ETIMEDOUT, "ETIMEDOUT"),
(errno.EINTR, "EINTR"),
(errno.ECHILD, "ECHILD"),
(errno.ESRCH, "ESRCH"),
(999, "(noma'lum)"),
]
print(f" {'errno':<8} {'Nomi':<16} {'Natija turi'}")
print(" " + "─" * 52)
for kod, nom in KODLAR:
e = OSError(kod, "xabar")
print(f" {kod:<8} {nom:<16} {type(e).__name__}")
print(f"""
⭐ MEXANIZM: OSError.__new__ errno ga qarab TO'G'RI
avlodni qaytaradi. Bu C darajasida amalga oshirilgan.
⭐ NATIJA: kutubxonalar OSError(errno, msg) ko'tarsa —
foydalanuvchi FileNotFoundError ni ushlaydi.
""")
print("=== 5. ⭐ Guruh ushlash imkoniyatlari ===\n")
GURUHLAR = [
(LookupError, "Qidiruv xatolari"),
(ArithmeticError, "Arifmetik xatolar"),
(OSError, "Tizim xatolari"),
(ConnectionError, "Ulanish xatolari"),
(ValueError, "Qiymat xatolari"),
(RuntimeError, "Ish vaqti xatolari"),
(NameError, "Nom xatolari"),
(ImportError, "Import xatolari"),
(SyntaxError, "Sintaksis xatolari"),
(UnicodeError, "Unicode xatolari"),
(Warning, "Ogohlantirishlar"),
]
for Guruh, tavsif in GURUHLAR:
a = sorted(S.__name__ for S in barcha(Guruh) if S is not Guruh)
print(f" except {Guruh.__name__:<18} — {tavsif}")
if a:
print(f" → {', '.join(a[:6])}"
f"{f' (+{len(a) - 6})' if len(a) > 6 else ''}")
print()
print("=== 6. ⚠️ Kutilmagan meroslar ===\n")
TEKSHIRUVLAR = [
("ModuleNotFoundError", ModuleNotFoundError, ImportError),
("UnboundLocalError", UnboundLocalError, NameError),
("RecursionError", RecursionError, RuntimeError),
("NotImplementedError", NotImplementedError, RuntimeError),
("UnicodeDecodeError", UnicodeDecodeError, ValueError),
("IndentationError", IndentationError, SyntaxError),
("TabError", TabError, IndentationError),
("TimeoutError", TimeoutError, OSError),
("StopIteration", StopIteration, Exception),
("KeyboardInterrupt", KeyboardInterrupt, Exception),
("SystemExit", SystemExit, Exception),
("MemoryError", MemoryError, Exception),
("Warning", Warning, Exception),
]
print(f" {'Istisno':<22} {'Kutilgan asos':<20} {'Haqiqat'}")
print(" " + "─" * 56)
for nom, Sinf, Kutilgan in TEKSHIRUVLAR:
natija = issubclass(Sinf, Kutilgan)
belgi = "✅" if natija else "❌"
print(f" {nom:<22} {Kutilgan.__name__:<20} {belgi}")
print(f"""
⚠️ ❌ BELGILANGANLAR:
KeyboardInterrupt, SystemExit — Exception EMAS!
→ BaseException avlodlari (9.6-dars, Vazifa 7)
⭐ QIZIQ FAKTLAR:
• NotImplementedError — RuntimeError avlodi
(⚠️ "TypeError kabi" tuyuladi, lekin yo'q)
• TimeoutError — OSError avlodi (3.3 dan)
(⚠️ asyncio.TimeoutError esa 3.11 dan shu bilan bir xil)
• RecursionError — 3.5 dan alohida (oldin RuntimeError)
• UnicodeDecodeError — ValueError avlodi
• MemoryError — Exception (Java da esa Error!)
""")
print("=== 7. ⭐ Ierarxiya bo'yicha qidiruv ===\n")
def qayerda(Sinf: type) -> str:
"""⭐ MRO yo'lini ko'rsatadi."""
yol = [K.__name__ for K in reversed(Sinf.__mro__[:-1])]
return " → ".join(yol)
SINOVLAR = [FileNotFoundError, ConnectionResetError, TabError,
UnicodeDecodeError, ModuleNotFoundError,
RecursionError, KeyError, TimeoutError]
for S in SINOVLAR:
print(f" {S.__name__}:")
print(f" {qayerda(S)}")
print()
print(f" ⭐ Bir istisnoni ushlash usullari (FileNotFoundError):\n")
for K in FileNotFoundError.__mro__[:-1]:
print(f" except {K.__name__}:")Natijaning muhim qismi:
=== 2. ⭐ Statistika ===
Jami o'rnatilgan istisno: 69
Daraja Soni Misollar
──────────────────────────────────────────────────────────────────
0 1 BaseException
1 5 BaseExceptionGroup, Exception, GeneratorExit, KeyboardInterrupt, SystemExit
2 19 ArithmeticError, AssertionError, AttributeError, BufferError, EOFError ...
3 36 BlockingIOError, BytesWarning, ChildProcessError, ConnectionError, DeprecationWarning ...
4 8 BrokenPipeError, ConnectionAbortedError, ConnectionRefusedError, ConnectionResetError, TabError ...
⭐ XULOSA: ko'pchilik istisno 1-3 daraja chuqurlikda.
Eng chuqur: 4 daraja.
=== 4. ⭐ OSError oilasi ===
errno Nomi Natija turi
────────────────────────────────────────────────────
2 ENOENT FileNotFoundError
13 EACCES PermissionError
111 ECONNREFUSED ConnectionRefusedError
999 (noma'lum) OSError
=== 6. ⚠️ Kutilmagan meroslar ===
KeyboardInterrupt Exception ❌
SystemExit Exception ❌
NotImplementedError RuntimeError ✅ Natija Python 3.14 da olingan. Istisnolar soni versiyaga qarab farq qiladi — masalan, PythonFinalizationError 3.13 da qo'shilgan. errno raqamlari esa platformaga bog'liq: yuqoridagi 111 (ECONNREFUSED) Linux qiymati, Windows'da xuddi shu konstanta 10061 ga teng. Shuning uchun kodda hech qachon raqam yozmang — errno.ECONNREFUSED ishlating.
Nima ko'rsatdi: 2.1, 2.4-bo'limlar.
Misol 2 — Ierarxiya loyihalash
"""Bir xil domen — uch xil ierarxiya. Qaysi biri yaxshi?"""
from __future__ import annotations
print("=== FAYL SAQLASH XIZMATI — UCH LOYIHA ===\n")
# ═══════════════════════════════════════════════
# ❌ LOYIHA A — TEKIS
# ═══════════════════════════════════════════════
class A_FaylTopilmadi(Exception): ...
class A_RuxsatYoq(Exception): ...
class A_JoyYoq(Exception): ...
class A_NomNotogri(Exception): ...
class A_HajmKatta(Exception): ...
class A_TurNotogri(Exception): ...
class A_UlanmadiXato(Exception): ...
class A_VaqtTugadi(Exception): ...
class A_KvotaOshdi(Exception): ...
# ═══════════════════════════════════════════════
# ❌ LOYIHA B — JUDA CHUQUR
# ═══════════════════════════════════════════════
class B_Xato(Exception): ...
class B_Kirish(B_Xato): ...
class B_KirishFayl(B_Kirish): ...
class B_KirishFaylOqish(B_KirishFayl): ...
class B_FaylTopilmadi(B_KirishFaylOqish): ... # 5 daraja
class B_KirishFaylYozish(B_KirishFayl): ...
class B_JoyYoq(B_KirishFaylYozish): ... # 5 daraja
class B_KirishRuxsat(B_Kirish): ...
class B_RuxsatYoq(B_KirishRuxsat): ... # 4 daraja
class B_Tekshirish(B_Xato): ...
class B_TekshirishNom(B_Tekshirish): ...
class B_NomNotogri(B_TekshirishNom): ... # 4 daraja
# ═══════════════════════════════════════════════
# ✅ LOYIHA C — MUVOZANATLI
# ═══════════════════════════════════════════════
class SaqlashXatosi(Exception):
"""Barcha saqlash xatolarining asosi."""
QAYTA_URINISH = False
HTTP_KODI = 500
class FaylXatosi(SaqlashXatosi):
"""Fayl bilan bog'liq (topilmadi, ruxsat, tur)."""
HTTP_KODI = 400
class ResursXatosi(SaqlashXatosi):
"""Resurs chegaralari (joy, kvota, hajm)."""
HTTP_KODI = 507
class TarmoqXatosi(SaqlashXatosi):
"""Tarmoq va tashqi xizmat."""
QAYTA_URINISH = True
HTTP_KODI = 503
class FaylTopilmadi(FaylXatosi):
"""So'ralgan fayl mavjud emas."""
HTTP_KODI = 404
def __init__(self, yol: str):
self.yol = yol
super().__init__(f"Fayl topilmadi: {yol}")
class RuxsatYoq(FaylXatosi):
"""Faylga kirish taqiqlangan."""
HTTP_KODI = 403
def __init__(self, yol: str, amal: str = "o'qish"):
self.yol, self.amal = yol, amal
super().__init__(f"Ruxsat yo'q: {amal} — {yol}")
class FaylNotogri(FaylXatosi):
"""Fayl nomi yoki turi yaroqsiz.
⭐ ATRIBUT bilan — uch sinf o'rniga bittasi.
"""
def __init__(self, yol: str, sabab: str, tafsilot: str = ""):
self.yol, self.sabab, self.tafsilot = yol, sabab, tafsilot
super().__init__(
f"Fayl yaroqsiz ({sabab}): {yol}"
+ (f" — {tafsilot}" if tafsilot else "")
)
class ChegaraOshdi(ResursXatosi):
"""Biror chegara oshdi.
⭐ ATRIBUT bilan: joy / kvota / hajm / fayllar soni.
"""
def __init__(self, tur: str, chegara: float, joriy: float,
birlik: str = ""):
self.tur, self.chegara, self.joriy = tur, chegara, joriy
self.birlik = birlik
self.oshgan = joriy - chegara
super().__init__(
f"{tur} chegarasi oshdi: {joriy:,.0f}/"
f"{chegara:,.0f} {birlik}".strip()
)
class UlanmadiXato(TarmoqXatosi):
"""Saqlash xizmatiga ulanib bo'lmadi."""
def __init__(self, xizmat: str, urinish: int = 1):
self.xizmat, self.urinish = xizmat, urinish
super().__init__(f"Ulanib bo'lmadi: {xizmat}")
class VaqtTugadi(TarmoqXatosi):
"""Amal belgilangan vaqtda bajarilmadi."""
HTTP_KODI = 504
def __init__(self, amal: str, sekund: float):
self.amal, self.sekund = amal, sekund
super().__init__(f"Vaqt tugadi: {amal} ({sekund}s)")
# ═══════════════════════════════════════════════
# TAHLIL
# ═══════════════════════════════════════════════
def yigish(Asos: type) -> list[type]:
natija = [Asos]
for A in Asos.__subclasses__():
natija.extend(yigish(A))
return natija
def maks_chuqurlik(Asos: type) -> int:
a = Asos.__subclasses__()
return 1 + max((maks_chuqurlik(A) for A in a), default=0)
def ierarxiya_chiz(Asos: type, chuqurlik: int = 0) -> list[str]:
q = [f"{' ' * chuqurlik}{'└─ ' if chuqurlik else ''}"
f"{Asos.__name__}"]
for A in sorted(Asos.__subclasses__(), key=lambda c: c.__name__):
q.extend(ierarxiya_chiz(A, chuqurlik + 1))
return q
print("1. Loyiha C ierarxiyasi:\n")
for q in ierarxiya_chiz(SaqlashXatosi):
print(f" {q}")
print("\n\n2. ⭐ Uch loyiha taqqoslash:\n")
A_SINFLAR = [A_FaylTopilmadi, A_RuxsatYoq, A_JoyYoq, A_NomNotogri,
A_HajmKatta, A_TurNotogri, A_UlanmadiXato,
A_VaqtTugadi, A_KvotaOshdi]
TAQQOS = [
("A — TEKIS", len(A_SINFLAR), 1, 0,
"❌ Guruh ushlash MUMKIN EMAS"),
("B — CHUQUR", len(yigish(B_Xato)), maks_chuqurlik(B_Xato), 4,
"❌ Chalkash, bo'sh oraliq sinflar"),
("C — MUVOZANATLI", len(yigish(SaqlashXatosi)),
maks_chuqurlik(SaqlashXatosi), 3,
"✅ Toifalar aniq, atributlar bilan"),
]
print(f" {'Loyiha':<18} {'Sinflar':<10} {'Chuqurlik':<11} "
f"{'Toifalar':<11} {'Baho'}")
print(" " + "─" * 78)
for nom, s, c, t, baho in TAQQOS:
print(f" {nom:<18} {s:<10} {c:<11} {t:<11} {baho}")
print("\n\n3. ⚠️ LOYIHA A muammosi:\n")
print(""" Foydalanuvchi kodi:
try:
saqla(fayl)
except A_FaylTopilmadi: ...
except A_RuxsatYoq: ...
except A_JoyYoq: ...
except A_NomNotogri: ...
except A_HajmKatta: ...
except A_TurNotogri: ...
except A_UlanmadiXato: ...
except A_VaqtTugadi: ...
except A_KvotaOshdi: ... ⚠️ 9 ta blok!
⚠️ MUAMMOLAR:
• Yangi istisno qo'shilsa — kod BUZILADI
• "Hammasini ushlash" mumkin emas
• except Exception: — juda keng
""")
print("4. ⚠️ LOYIHA B muammosi:\n")
print(f" B_FaylTopilmadi MRO:")
for K in B_FaylTopilmadi.__mro__[:-1]:
print(f" {K.__name__}")
print("""
⚠️ MUAMMOLAR:
• B_KirishFaylOqish — hech kim ushlamaydi (bo'sh oraliq)
• "Kirish" toifasi juda keng (fayl + ruxsat)
• Yangi istisnoni QAYERGA qo'yish noaniq
• Nomlar uzun va chalkash
""")
print("5. ✅ LOYIHA C — foydalanuvchi tanlaydi:\n")
XATOLAR = [
FaylTopilmadi("/hujjatlar/hisobot.pdf"),
RuxsatYoq("/tizim/config.json", "yozish"),
FaylNotogri("rasm.exe", "tur", "faqat jpg, png, pdf"),
FaylNotogri("a" * 300 + ".txt", "nom", "255 belgidan uzun"),
ChegaraOshdi("Disk", 10_000, 10_240, "MB"),
ChegaraOshdi("Kvota", 1_000, 1_050, "fayl"),
ChegaraOshdi("Hajm", 50, 120, "MB"),
UlanmadiXato("s3.wisar.uz", urinish=2),
VaqtTugadi("yuklash", 30.0),
]
print(f" Uch daraja aniqlik:\n")
for Tur, tavsif in [
(SaqlashXatosi, "HAMMASI"),
(FaylXatosi, "Fayl toifasi"),
(ResursXatosi, "Resurs toifasi"),
(TarmoqXatosi, "Tarmoq toifasi"),
(FaylTopilmadi, "Aniq xato"),
]:
mos = [e for e in XATOLAR if isinstance(e, Tur)]
print(f" except {Tur.__name__:<16} ({tavsif:<14}) "
f"→ {len(mos)} xato")
print("\n\n6. ⭐ Atribut vs sinf qarori:\n")
print(""" LOYIHA A da uch alohida sinf edi:
A_NomNotogri, A_TurNotogri, A_HajmKatta
LOYIHA C da:
FaylNotogri(sabab="nom" | "tur") ⭐ 1 sinf
ChegaraOshdi(tur="Hajm") ⭐ 1 sinf
⭐ QAROR MEZONI:
"Foydalanuvchi bularni ALOHIDA ushlaydimi?"
• Nom noto'g'ri → foydalanuvchi tuzatadi
• Tur noto'g'ri → foydalanuvchi tuzatadi
⭐ BIR XIL ish → BITTA sinf, sabab atributi
• Fayl topilmadi → 404
• Ruxsat yo'q → 403
⭐ HAR XIL ish → ALOHIDA sinf
""")
print(f" Amalda:\n")
for e in XATOLAR:
ish = ""
if isinstance(e, FaylNotogri):
ish = f"Foydalanuvchiga: '{e.sabab}' ni tuzating"
elif isinstance(e, ChegaraOshdi):
ish = f"{e.tur}: {e.oshgan:,.0f} {e.birlik} ortiqcha"
elif isinstance(e, FaylTopilmadi):
ish = "404 qaytarish"
elif isinstance(e, RuxsatYoq):
ish = "403 qaytarish"
elif isinstance(e, TarmoqXatosi):
ish = "Qayta urinish"
print(f" HTTP {e.HTTP_KODI} {type(e).__name__:<16} {ish}")
print("\n\n7. ⭐ Ierarxiya tekshiruvchisi:\n")
def ierarxiya_tekshir(Asos: type) -> list[tuple[str, str]]:
"""⭐ Loyihalash muammolarini topadi."""
muammolar: list[tuple[str, str]] = []
def yur(S: type, chuqurlik: int = 0):
avlodlar = S.__subclasses__()
if chuqurlik > 3:
muammolar.append(
("CHUQUR", f"{S.__name__} — {chuqurlik} daraja")
)
if len(avlodlar) > 12:
muammolar.append(
("KENG", f"{S.__name__} — {len(avlodlar)} avlod")
)
if len(avlodlar) == 1:
muammolar.append(
("BITTA", f"{S.__name__} — bitta avlod "
f"({avlodlar[0].__name__}), birlashtiring?")
)
if not (S.__doc__ or "").strip():
muammolar.append(("HUJJAT", f"{S.__name__} — docstring yo'q"))
for A in avlodlar:
yur(A, chuqurlik + 1)
yur(Asos)
return muammolar
for nom, Asos in [("LOYIHA B", B_Xato), ("LOYIHA C", SaqlashXatosi)]:
m = ierarxiya_tekshir(Asos)
print(f" {nom}: {len(m)} muammo")
for tur, matn in m[:8]:
print(f" [{tur:<7}] {matn}")
if len(m) > 8:
print(f" ... va yana {len(m) - 8} ta")
print()Natijaning muhim qismi:
1. Loyiha C ierarxiyasi:
SaqlashXatosi
└─ FaylXatosi
└─ FaylNotogri
└─ FaylTopilmadi
└─ RuxsatYoq
└─ ResursXatosi
└─ ChegaraOshdi
└─ TarmoqXatosi
└─ UlanmadiXato
└─ VaqtTugadi
2. ⭐ Uch loyiha taqqoslash:
Loyiha Sinflar Chuqurlik Toifalar Baho
──────────────────────────────────────────────────────────────────────────
A — TEKIS 9 1 0 ❌ Guruh ushlash MUMKIN EMAS
B — CHUQUR 12 5 4 ❌ Chalkash, bo'sh oraliq sinflar
C — MUVOZANATLI 10 3 3 ✅ Toifalar aniq, atributlar bilan
5. ✅ LOYIHA C — foydalanuvchi tanlaydi:
except SaqlashXatosi (HAMMASI ) → 9 xato
except FaylXatosi (Fayl toifasi ) → 4 xato
except ResursXatosi (Resurs toifasi) → 3 xato
except FaylTopilmadi (Aniq xato ) → 1 xatoNima ko'rsatdi: 2.2, 2.3, 2.7-bo'limlar.
Misol 3 — Migratsiya va orqaga moslik
"""Ierarxiyani versiyadan versiyaga o'zgartirish."""
from __future__ import annotations
import warnings
warnings.simplefilter("always", DeprecationWarning)
print("=== 1. ⭐ v1.0 — boshlang'ich ===\n")
class V1_KutubxonaXatosi(Exception):
"""Asos."""
class V1_UlanmadiXato(V1_KutubxonaXatosi):
"""Ulanib bo'lmadi."""
class V1_VaqtTugadi(V1_KutubxonaXatosi):
"""Vaqt tugadi."""
class V1_NotogriMalumot(V1_KutubxonaXatosi):
"""Ma'lumot yaroqsiz."""
print(""" V1_KutubxonaXatosi
├── V1_UlanmadiXato
├── V1_VaqtTugadi
└── V1_NotogriMalumot
⚠️ MUAMMO: tarmoq xatolarini birga ushlash mumkin emas.
""")
print("=== 2. ✅ v2.0 — TOIFA QO'SHISH (xavfsiz) ===\n")
class V2_KutubxonaXatosi(Exception):
"""Asos — o'zgarmadi."""
class V2_TarmoqXatosi(V2_KutubxonaXatosi):
"""⭐ YANGI oraliq toifa."""
class V2_UlanmadiXato(V2_TarmoqXatosi):
"""⭐ Asosi O'ZGARDI, lekin KENGAYDI."""
class V2_VaqtTugadi(V2_TarmoqXatosi):
"""⭐ Asosi O'ZGARDI, lekin KENGAYDI."""
class V2_NotogriMalumot(V2_KutubxonaXatosi):
"""O'zgarmadi."""
e = V2_UlanmadiXato("xato")
print(f" Eski kod: except V2_KutubxonaXatosi:")
print(f" Ishlaydimi? {isinstance(e, V2_KutubxonaXatosi)} ✅")
print(f"\n Yangi kod: except V2_TarmoqXatosi:")
print(f" Ishlaydimi? {isinstance(e, V2_TarmoqXatosi)} ✅")
print(f"""
⭐ NEGA XAVFSIZ:
V1: UlanmadiXato → KutubxonaXatosi
V2: UlanmadiXato → TarmoqXatosi → KutubxonaXatosi
⭐ QO'SHILDI
MRO KENGAYDI — eski asos hamon MRO da.
Eski except bloklar ishlashda davom etadi.
⭐ QOIDA: oraliq sinf QO'SHISH — har doim xavfsiz.
""")
print("=== 3. ❌ v3.0 — ASOSNI ALMASHTIRISH (buzadi) ===\n")
class V3_TarmoqXatosi(Exception):
"""⚠️ KutubxonaXatosi'dan CHIQDI."""
class V3_UlanmadiXato(V3_TarmoqXatosi):
"""⚠️ Endi V2_KutubxonaXatosi emas."""
e3 = V3_UlanmadiXato("xato")
print(f" Eski kod: except V2_KutubxonaXatosi:")
print(f" Ishlaydimi? {isinstance(e3, V2_KutubxonaXatosi)} ❌ BUZILDI")
print(f"""
❌ BU BUZUVCHI O'ZGARISH:
Foydalanuvchining ISHLAYOTGAN kodi:
try:
kutubxona.sorov()
except KutubxonaXatosi: ⚠️ ENDI USHLAMAYDI
qayta_urin()
→ Istisno DASTURNI TO'XTATADI
⭐ QOIDA: MRO dan sinf OLIB TASHLAMANG.
""")
print("=== 4. ⭐ Ko'p meros bilan migratsiya ===\n")
class V4_KutubxonaXatosi(Exception):
"""Yangi asos."""
class V4_NotogriMalumot(V4_KutubxonaXatosi, ValueError):
"""⭐ Eski kod ValueError ni ushlagan edi.
Ko'p meros — IKKALASI ham ishlaydi.
"""
e4 = V4_NotogriMalumot("yaroqsiz")
print(f" MRO: {[K.__name__ for K in type(e4).__mro__[:4]]}\n")
print(f" {'Ushlash usuli':<32} {'Ishlaydimi'}")
print(" " + "─" * 48)
for Tur in (V4_NotogriMalumot, V4_KutubxonaXatosi, ValueError,
Exception):
print(f" except {Tur.__name__:<24} {isinstance(e4, Tur)}")
print(f"""
⭐ STRATEGIYA:
v1.0: raise ValueError("yaroqsiz")
v2.0: raise NotogriMalumot(...) ⭐ ValueError dan meros
v3.0: (2 yil keyin) ValueError olib tashlanadi
⚠️ EHTIYOT: ko'p meros MRO ni murakkablashtiradi.
__str__ va __init__ ni tekshiring.
""")
print("=== 5. ⭐ DeprecationWarning bilan ===\n")
class YangiXato(Exception):
"""Yangi nom."""
class EskiXato(YangiXato):
"""⚠️ Eskirgan — YangiXato ishlating."""
def __init__(self, *args, **kwargs):
warnings.warn(
"EskiXato eskirgan, YangiXato ishlating "
"(v4.0 da olib tashlanadi)",
DeprecationWarning,
stacklevel=2,
)
super().__init__(*args, **kwargs)
print(f" Eski sinfdan foydalanish:")
with warnings.catch_warnings(record=True) as ogohlar:
warnings.simplefilter("always")
e5 = EskiXato("xabar")
for o in ogohlar:
print(f" ⚠️ {o.category.__name__}: {o.message}")
print(f"\n Ushlash hamon ishlaydi:")
try:
raise EskiXato("test")
except YangiXato as e:
print(f" except YangiXato → ushlandi ✅")
print(f"""
⚠️ MUHIM: ogohlantirish YARATILGANDA chiqadi, USHLANGANDA emas.
except EskiXato: ⚠️ ogohlantirish YO'Q
raise EskiXato(...) ⭐ ogohlantirish BOR
⭐ Ushlashni ham ogohlantirish uchun — metaklass kerak
(__instancecheck__ ni ushlash), lekin bu ODATDA ORTIQCHA.
""")
print("=== 6. ⭐ Taxallus va __init__ eksporti ===\n")
# ⭐ Eng oddiy migratsiya
SorovXatosi = YangiXato # taxallus
print(f" SorovXatosi is YangiXato → {SorovXatosi is YangiXato}")
print(f" ⭐ Bir XIL obyekt — hech qanday farq yo'q\n")
print(""" Modul tuzilishi:
# xatolar.py
class KutubxonaXatosi(Exception): ...
class TarmoqXatosi(KutubxonaXatosi): ...
class VaqtTugadi(TarmoqXatosi): ...
# ⚠️ Eskirgan taxalluslar
SorovXatosi = KutubxonaXatosi
UlanishXatosi = TarmoqXatosi
__all__ = [
"KutubxonaXatosi", "TarmoqXatosi", "VaqtTugadi",
# eskirganlar __all__ da EMAS
]
# __init__.py
from .xatolar import *
from .xatolar import SorovXatosi, UlanishXatosi ⭐ aniq
""")
print("=== 7. ⭐ Migratsiya rejasi ===\n")
REJA = [
("v1.5", "Yangi ierarxiya QO'SHILADI",
"Eski sinflar yangilardan meros oladi", "✅ Buzmaydi"),
("v2.0", "Hujjatda yangi nomlar",
"Eskilar hamon ishlaydi, ogohlantirishsiz", "✅ Buzmaydi"),
("v2.5", "DeprecationWarning qo'shiladi",
"Foydalanuvchi ogohlantiriladi", "⚠️ Ogohlantirish"),
("v3.0", "CHANGELOG da katta e'lon",
"Eskilar 1 yil ishlaydi", "⚠️ Ogohlantirish"),
("v4.0", "Eski nomlar OLIB TASHLANADI",
"Major versiya — buzuvchi o'zgarish", "❌ Buzadi"),
]
print(f" {'Versiya':<9} {'Qadam':<34} {'Ta`sir'}")
print(" " + "─" * 66)
for v, qadam, izoh, tasir in REJA:
print(f" {v:<9} {qadam:<34} {tasir}")
print(f" {'':<9} {izoh}")
print()
print(""" ⭐ SEMVER (semver.org) QOIDASI:
PATCH (1.0.1) — ierarxiya O'ZGARMAYDI
MINOR (1.1.0) — sinf QO'SHISH, oraliq toifa QO'SHISH
MAJOR (2.0.0) — sinf OLIB TASHLASH, asosni TORAYTIRISH
⭐ AMALIY MASLAHAT:
• Kutubxona chiqarishdan OLDIN ierarxiyani o'ylang
• Bitta asos sinfdan boshlang
• Toifalarni KEYIN qo'shish oson
• Toifani OLIB TASHLASH qiyin
""")
print("=== 8. ⭐ Ierarxiya testi ===\n")
class KutubxonaXatosi(Exception):
"""Asos."""
class TarmoqXatosi(KutubxonaXatosi):
"""Tarmoq."""
class VaqtTugadi(TarmoqXatosi):
"""Vaqt."""
class MalumotXatosi(KutubxonaXatosi):
"""Ma'lumot."""
def test_ierarxiya():
"""⭐ Bu testlar ierarxiyani MUZLATADI.
Kelajakdagi o'zgarishlar buzsa — test qulaydi.
"""
natijalar = []
# ⭐ 1. Barcha istisnolar asosdan meros
for S in (TarmoqXatosi, VaqtTugadi, MalumotXatosi):
ok = issubclass(S, KutubxonaXatosi)
natijalar.append((f"{S.__name__} ⊂ KutubxonaXatosi", ok))
# ⭐ 2. Asos — Exception, BaseException emas
ok = (issubclass(KutubxonaXatosi, Exception)
and KutubxonaXatosi is not BaseException)
natijalar.append(("Asos — Exception avlodi", ok))
# ⭐ 3. Toifalar to'g'ri
natijalar.append((
"VaqtTugadi ⊂ TarmoqXatosi",
issubclass(VaqtTugadi, TarmoqXatosi),
))
natijalar.append((
"MalumotXatosi ⊄ TarmoqXatosi",
not issubclass(MalumotXatosi, TarmoqXatosi),
))
# ⭐ 4. Chuqurlik chegarasi
def chuq(S):
return len([K for K in S.__mro__
if issubclass(K, KutubxonaXatosi)])
eng = max(chuq(S) for S in (TarmoqXatosi, VaqtTugadi,
MalumotXatosi))
natijalar.append((f"Chuqurlik ≤ 3 (joriy: {eng})", eng <= 3))
# ⭐ 5. Har sinfda docstring
hammasi = all(
(S.__doc__ or "").strip()
for S in (KutubxonaXatosi, TarmoqXatosi, VaqtTugadi,
MalumotXatosi)
)
natijalar.append(("Har sinfda docstring", hammasi))
# ⭐ 6. str(e) bo'sh emas
bosh_emas = all(
str(S("xabar")) == "xabar"
for S in (TarmoqXatosi, VaqtTugadi, MalumotXatosi)
)
natijalar.append(("str(e) to'g'ri ishlaydi", bosh_emas))
return natijalar
print(f" {'Test':<42} {'Natija'}")
print(" " + "─" * 54)
for nom, ok in test_ierarxiya():
print(f" {nom:<42} {'✅ PASS' if ok else '❌ FAIL'}")
print(f"""
⭐ NEGA IERARXIYA TESTLARI KERAK:
• Refaktoring paytida tasodifan buzilishi mumkin
• Yangi dasturchi noto'g'ri joyga qo'shishi mumkin
• Buzuvchi o'zgarishlar TESTDA ko'rinadi
• Hujjat vazifasini bajaradi
⚠️ pytest da:
@pytest.mark.parametrize("Sinf", [TarmoqXatosi, VaqtTugadi])
def test_asos(Sinf):
assert issubclass(Sinf, KutubxonaXatosi)
""")Natijaning muhim qismi:
=== 2. ✅ v2.0 — TOIFA QO'SHISH (xavfsiz) ===
Eski kod: except V2_KutubxonaXatosi:
Ishlaydimi? True ✅
Yangi kod: except V2_TarmoqXatosi:
Ishlaydimi? True ✅
=== 3. ❌ v3.0 — ASOSNI ALMASHTIRISH (buzadi) ===
Eski kod: except V2_KutubxonaXatosi:
Ishlaydimi? False ❌ BUZILDI
=== 5. ⭐ DeprecationWarning bilan ===
Eski sinfdan foydalanish:
⚠️ DeprecationWarning: EskiXato eskirgan, YangiXato ishlating
(v4.0 da olib tashlanadi)
=== 8. ⭐ Ierarxiya testi ===
Test Natija
──────────────────────────────────────────────────────
TarmoqXatosi ⊂ KutubxonaXatosi ✅ PASS
Asos — Exception avlodi ✅ PASS
Chuqurlik ≤ 3 (joriy: 3) ✅ PASSNima ko'rsatdi: 2.6, 2.7-bo'limlar.
Misol 4 — Amaliy: IlmHamroh platformasi ierarxiyasi
"""To'liq platforma uchun istisno ierarxiyasi."""
from __future__ import annotations
import json
from dataclasses import dataclass
from datetime import datetime
from enum import Enum
from typing import Any, ClassVar
print("=== WISAR PLATFORMASI — ISTISNO IERARXIYASI ===\n")
class Qatlam(str, Enum):
"""⭐ Xato qaysi qatlamda yuzaga keldi."""
TAQDIMOT = "taqdimot" # HTTP, CLI
DOMEN = "domen" # biznes mantiq
INFRA = "infra" # DB, tarmoq, fayl
def __str__(self): return self.value
# ═══════════════════════════════════════════════
# 1-DARAJA: ASOS
# ═══════════════════════════════════════════════
class WisarXatosi(Exception):
"""⭐ Platformaning BARCHA xatolari.
Foydalanuvchi bitta blok bilan hammasini ushlaydi:
except WisarXatosi: ...
"""
QATLAM: ClassVar[Qatlam] = Qatlam.DOMEN
HTTP_KODI: ClassVar[int] = 500
QAYTA_URINISH: ClassVar[bool] = False
OMMAVIY: ClassVar[bool] = False # foydalanuvchiga ko'rsatiladimi
XABAR: ClassVar[str] = "Xato yuz berdi"
def __init__(self, xabar: str = "", **kontekst: Any):
self.kontekst = kontekst
self.vaqt = datetime.now()
super().__init__(xabar or self.XABAR)
def __str__(self) -> str:
asos = self.args[0] if self.args else self.XABAR
if not self.kontekst:
return asos
k = ", ".join(f"{a}={b!r}" for a, b in self.kontekst.items())
return f"{asos} ({k})"
def javob(self) -> tuple[int, dict]:
return self.HTTP_KODI, {
"xato": type(self).__name__,
"xabar": (str(self) if self.OMMAVIY else self.XABAR),
"qatlam": str(self.QATLAM),
}
# ═══════════════════════════════════════════════
# 2-DARAJA: TOIFALAR (6 ta)
# ═══════════════════════════════════════════════
class SorovXatosi(WisarXatosi):
"""Kiruvchi so'rov bilan bog'liq — mijoz aybi."""
QATLAM = Qatlam.TAQDIMOT
HTTP_KODI = 400
OMMAVIY = True
XABAR = "So'rov noto'g'ri"
class RuxsatXatosi(WisarXatosi):
"""Autentifikatsiya va avtorizatsiya."""
QATLAM = Qatlam.TAQDIMOT
HTTP_KODI = 403
OMMAVIY = True
XABAR = "Ruxsat yo'q"
class BiznesXatosi(WisarXatosi):
"""Biznes qoidasi buzildi — mijoz tuzatishi mumkin."""
QATLAM = Qatlam.DOMEN
HTTP_KODI = 409
OMMAVIY = True
XABAR = "Amal bajarib bo'lmadi"
class MalumotXatosi(WisarXatosi):
"""Ma'lumotlar bazasi bilan bog'liq."""
QATLAM = Qatlam.INFRA
HTTP_KODI = 500
XABAR = "Ma'lumotlar bazasi xatosi"
class TashqiXizmatXatosi(WisarXatosi):
"""Tashqi API va xizmatlar."""
QATLAM = Qatlam.INFRA
HTTP_KODI = 502
QAYTA_URINISH = True
XABAR = "Tashqi xizmat javob bermadi"
class SozlamaXatosi(WisarXatosi):
"""Noto'g'ri konfiguratsiya — dasturchi aybi."""
QATLAM = Qatlam.INFRA
HTTP_KODI = 500
XABAR = "Tizim sozlamasi xato"
# ═══════════════════════════════════════════════
# 3-DARAJA: ANIQ XATOLAR
# ═══════════════════════════════════════════════
# ── So'rov ──
class ValidatsiyaXatosi(SorovXatosi):
"""Kiruvchi ma'lumot yaroqsiz."""
HTTP_KODI = 422
def __init__(self, maydon: str, sabab: str):
self.maydon, self.sabab = maydon, sabab
super().__init__(f"{maydon}: {sabab}", maydon=maydon)
class TopilmadiXatosi(SorovXatosi):
"""So'ralgan resurs mavjud emas."""
HTTP_KODI = 404
def __init__(self, tur: str, id_: Any):
self.tur, self.id = tur, id_
super().__init__(f"{tur} topilmadi", tur=tur, id=id_)
class TezlikChegarasi(SorovXatosi):
"""So'rovlar chegarasi oshdi."""
HTTP_KODI = 429
def __init__(self, chegara: int, kutish: float = 60.0):
self.chegara, self.kutish = chegara, kutish
super().__init__(f"Chegara: {chegara} so'rov/daqiqa",
kutish=kutish)
# ── Ruxsat ──
class AutentifikatsiyaXatosi(RuxsatXatosi):
"""Kim ekanligi tasdiqlanmadi."""
HTTP_KODI = 401
XABAR = "Tizimga kiring"
class HuquqYetarliEmas(RuxsatXatosi):
"""Kim ekanligi ma'lum, lekin huquq yo'q."""
def __init__(self, kerak: str):
self.kerak = kerak
super().__init__(f"Huquq kerak: {kerak}", kerak=kerak)
# ── Biznes ──
class TakrorYozuv(BiznesXatosi):
"""Bunday yozuv allaqachon mavjud."""
def __init__(self, tur: str, maydon: str, qiymat: Any):
self.tur, self.maydon = tur, maydon
super().__init__(f"{tur} mavjud: {maydon}={qiymat!r}",
tur=tur, maydon=maydon)
class HolatNotogri(BiznesXatosi):
"""Obyekt bu amal uchun noto'g'ri holatda."""
def __init__(self, obyekt: str, joriy: str, kerak: str):
self.obyekt, self.joriy, self.kerak = obyekt, joriy, kerak
super().__init__(
f"{obyekt} holati '{joriy}', '{kerak}' bo'lishi kerak",
obyekt=obyekt,
)
class BogliqlikXatosi(BiznesXatosi):
"""Boshqa yozuvlar bunga bog'liq."""
def __init__(self, tur: str, bogliq_soni: int):
self.tur, self.bogliq_soni = tur, bogliq_soni
super().__init__(
f"{tur} o'chirib bo'lmaydi: {bogliq_soni} ta bog'liq yozuv",
tur=tur,
)
# ── Ma'lumot ──
class UlanmadiXato(MalumotXatosi):
"""Bazaga ulanib bo'lmadi."""
QAYTA_URINISH = True
HTTP_KODI = 503
def __init__(self, baza: str, urinish: int = 1):
self.baza, self.urinish = baza, urinish
super().__init__(f"Bazaga ulanib bo'lmadi: {baza}",
urinish=urinish)
class TranzaksiyaXatosi(MalumotXatosi):
"""Tranzaksiya bekor qilindi."""
QAYTA_URINISH = True
def __init__(self, sabab: str, qaytarildi: bool = True):
self.sabab, self.qaytarildi = sabab, qaytarildi
super().__init__(f"Tranzaksiya bekor: {sabab}",
qaytarildi=qaytarildi)
class SorovVaqtTugadi(MalumotXatosi):
"""Baza so'rovi juda uzoq davom etdi."""
HTTP_KODI = 504
QAYTA_URINISH = True
def __init__(self, sekund: float, sorov: str = ""):
self.sekund = sekund
super().__init__(f"So'rov vaqti tugadi ({sekund}s)",
sekund=sekund)
# ── Tashqi xizmat ──
class XizmatMavjudEmas(TashqiXizmatXatosi):
"""Tashqi xizmat ishlamayapti."""
HTTP_KODI = 503
def __init__(self, xizmat: str, kod: int = 0):
self.xizmat, self.kod = xizmat, kod
super().__init__(f"{xizmat} mavjud emas", xizmat=xizmat)
class XizmatVaqtTugadi(TashqiXizmatXatosi):
"""Tashqi xizmat vaqtida javob bermadi."""
HTTP_KODI = 504
def __init__(self, xizmat: str, sekund: float):
self.xizmat, self.sekund = xizmat, sekund
super().__init__(f"{xizmat} vaqt tugadi ({sekund}s)",
xizmat=xizmat)
# ── Sozlama ──
class SozlamaYoq(SozlamaXatosi):
"""Majburiy sozlama berilmagan."""
def __init__(self, kalit: str):
self.kalit = kalit
super().__init__(f"Sozlama yo'q: {kalit}", kalit=kalit)
class SozlamaNotogri(SozlamaXatosi):
"""Sozlama qiymati yaroqsiz."""
def __init__(self, kalit: str, qiymat: Any, kutilgan: str):
self.kalit, self.qiymat = kalit, qiymat
super().__init__(
f"Sozlama noto'g'ri: {kalit}={qiymat!r}, "
f"kutilgan: {kutilgan}",
kalit=kalit,
)
# ═══════════════════════════════════════════════
# TAHLIL
# ═══════════════════════════════════════════════
print("1. Ierarxiya:\n")
def chiz(S: type, chuqurlik: int = 0) -> list[str]:
belgi = {"taqdimot": "🌐", "domen": "🏢", "infra": "⚙️"}[
str(S.QATLAM)
]
nom = f"{' ' * chuqurlik}{'└─ ' if chuqurlik else ''}{S.__name__}"
q = [f" {nom:<40} {belgi} {S.HTTP_KODI}"
f"{' 🔄' if S.QAYTA_URINISH else ''}"]
for A in sorted(S.__subclasses__(), key=lambda c: c.__name__):
q.extend(chiz(A, chuqurlik + 1))
return q
for q in chiz(WisarXatosi):
print(q)
print("\n\n2. ⭐ O'lchamlar:\n")
def barchasi(S):
n = [S]
for A in S.__subclasses__():
n.extend(barchasi(A))
return n
HAMMASI = barchasi(WisarXatosi)
TOIFALAR = WisarXatosi.__subclasses__()
def chuqurlik(S):
return len([K for K in S.__mro__ if issubclass(K, WisarXatosi)])
print(f" Jami sinf: {len(HAMMASI)}")
print(f" Toifalar: {len(TOIFALAR)}")
print(f" Aniq xatolar: {len(HAMMASI) - len(TOIFALAR) - 1}")
print(f" Maks chuqurlik: {max(chuqurlik(S) for S in HAMMASI)}")
print(f" Qayta urinish mumkin: "
f"{sum(1 for S in HAMMASI if S.QAYTA_URINISH)}")
print(f" Ommaviy xabar: "
f"{sum(1 for S in HAMMASI if S.OMMAVIY)}")
print("\n\n3. ⭐ Qatlamlar bo'yicha:\n")
for q in Qatlam:
mos = [S for S in HAMMASI if S.QATLAM is q and S.__subclasses__() == []]
belgi = {"taqdimot": "🌐", "domen": "🏢", "infra": "⚙️"}[str(q)]
print(f" {belgi} {str(q).upper():<12} ({len(mos)}):")
for S in sorted(mos, key=lambda c: c.__name__):
print(f" {S.__name__:<26} HTTP {S.HTTP_KODI}")
print()
print("4. ⭐ Ushlash strategiyalari:\n")
XATOLAR = [
ValidatsiyaXatosi("email", "format noto'g'ri"),
TopilmadiXatosi("Xodim", 999),
TezlikChegarasi(100, 45.0),
AutentifikatsiyaXatosi(),
HuquqYetarliEmas("admin"),
TakrorYozuv("Xodim", "email", "aziz@wisar.uz"),
HolatNotogri("Buyurtma", "yakunlangan", "kutilmoqda"),
BogliqlikXatosi("Bo'lim", 12),
UlanmadiXato("wisar-db", 2),
TranzaksiyaXatosi("deadlock"),
SorovVaqtTugadi(30.0),
XizmatMavjudEmas("payme-api", 503),
XizmatVaqtTugadi("eskiz-sms", 10.0),
SozlamaYoq("DATABASE_URL"),
SozlamaNotogri("PORT", "abc", "butun son"),
]
STRATEGIYALAR = [
("HTTP handler", [
(SorovXatosi, "4xx qaytarish — mijozga xabar"),
(RuxsatXatosi, "401/403 — qayta kirish"),
(BiznesXatosi, "409 — biznes xabari"),
(WisarXatosi, "500 — umumiy xabar + jurnal"),
]),
("Fon vazifasi", [
(TashqiXizmatXatosi, "Navbatga qaytarish"),
(MalumotXatosi, "Qayta urinish"),
(SozlamaXatosi, "Vazifani to'xtatish + ogohlantirish"),
]),
]
for nom, bloklar in STRATEGIYALAR:
print(f" {nom}:\n")
ushlangan: set = set()
for Tur, ish in bloklar:
mos = [e for e in XATOLAR
if isinstance(e, Tur) and id(e) not in ushlangan]
ushlangan |= {id(e) for e in mos}
print(f" except {Tur.__name__:<22} → {ish}")
print(f" {len(mos)} xato: "
f"{', '.join(type(e).__name__ for e in mos[:3])}"
f"{' ...' if len(mos) > 3 else ''}")
print()
print("5. ⭐ HTTP javoblar:\n")
print(f" {'Istisno':<24} {'HTTP':<6} {'Ommaviy':<9} {'Xabar'}")
print(" " + "─" * 78)
for e in XATOLAR:
kod, tana = e.javob()
print(f" {type(e).__name__:<24} {kod:<6} "
f"{'✅' if e.OMMAVIY else '🔒':<9} {tana['xabar'][:32]}")
print(f"""
⭐ OMMAVIY=False — texnik tafsilot YASHIRILADI:
Ichki: "Bazaga ulanib bo'lmadi: wisar-db (urinish=2)"
Tashqi: "Ma'lumotlar bazasi xatosi"
⚠️ NEGA: xato xabari SIR OSHKOR qilishi mumkin
(baza nomi, ichki IP, fayl yo'llari, SQL so'rovlar).
""")
print("6. ⭐ Qayta urinish qarori:\n")
print(f" {'Istisno':<24} {'Qayta urinish':<16} {'Sabab'}")
print(" " + "─" * 70)
for e in XATOLAR:
if e.QAYTA_URINISH:
sabab = "Vaqtinchalik — o'tib ketishi mumkin"
belgi = "🔄 HA"
elif isinstance(e, (SorovXatosi, RuxsatXatosi, BiznesXatosi)):
sabab = "Mijoz tuzatishi kerak"
belgi = "❌ YO'Q"
elif isinstance(e, SozlamaXatosi):
sabab = "Dasturchi tuzatishi kerak"
belgi = "❌ YO'Q"
else:
sabab = "Noma'lum — jurnalga"
belgi = "❌ YO'Q"
print(f" {type(e).__name__:<24} {belgi:<16} {sabab}")
print("\n\n7. ⭐ Ierarxiya testlari:\n")
def testlar() -> list[tuple[str, bool]]:
n = []
n.append(("Barcha sinflar WisarXatosi avlodi",
all(issubclass(S, WisarXatosi) for S in HAMMASI)))
n.append(("Asos — Exception (BaseException emas)",
issubclass(WisarXatosi, Exception)))
n.append((f"Chuqurlik ≤ 3 "
f"(joriy: {max(chuqurlik(S) for S in HAMMASI)})",
max(chuqurlik(S) for S in HAMMASI) <= 3))
n.append((f"Toifalar 2-8 orasida (joriy: {len(TOIFALAR)})",
2 <= len(TOIFALAR) <= 8))
n.append(("Har sinfda docstring",
all((S.__doc__ or "").strip() for S in HAMMASI)))
n.append(("Har sinfda HTTP_KODI 100-599",
all(100 <= S.HTTP_KODI <= 599 for S in HAMMASI)))
n.append(("Bo'sh oraliq sinf yo'q",
all(len(S.__subclasses__()) != 1 for S in HAMMASI)))
n.append(("4xx xatolar OMMAVIY",
all(S.OMMAVIY for S in HAMMASI
if 400 <= S.HTTP_KODI < 500)))
n.append(("5xx xatolar QAYTA_URINISH yoki SozlamaXatosi",
all(S.QAYTA_URINISH or issubclass(S, SozlamaXatosi)
or S in (WisarXatosi, MalumotXatosi)
for S in HAMMASI if S.HTTP_KODI >= 500)))
n.append(("str(e) hech qachon bo'sh emas",
all(str(S("test")) for S in (ValidatsiyaXatosi.__bases__
+ (WisarXatosi,)))))
return n
for nom, ok in testlar():
print(f" {'✅' if ok else '❌'} {nom}")
print(f"""
⭐ BU IERARXIYADA:
1-DARAJA: WisarXatosi
→ foydalanuvchi hammasini ushlashi mumkin
2-DARAJA: 6 toifa
So'rov / Ruxsat / Biznes / Ma'lumot / Tashqi / Sozlama
→ har biri HAR XIL ishlov talab qiladi
3-DARAJA: 15 aniq xato
→ atributlar bilan boy kontekst
⭐ QARORLAR:
• Chuqurlik 3 — ko'proq emas
• ClassVar sozlamalar merosda uzatiladi
• OMMAVIY — sirlarni himoya qiladi
• QAYTA_URINISH — avtomatik qaror
• QATLAM — monitoring va guruhlash uchun
⭐ KENGAYTIRISH:
Yangi xato → mos TOIFAGA qo'shiladi
Yangi toifa → WisarXatosi ostiga (kamdan-kam)
⚠️ Toifani OLIB TASHLASH — major versiya
""")Natijaning muhim qismi:
1. Ierarxiya:
WisarXatosi 🏢 500
└─ BiznesXatosi 🏢 409
└─ BogliqlikXatosi 🏢 409
└─ HolatNotogri 🏢 409
└─ TakrorYozuv 🏢 409
└─ MalumotXatosi ⚙️ 500
└─ SorovVaqtTugadi ⚙️ 504 🔄
└─ TranzaksiyaXatosi ⚙️ 500 🔄
└─ UlanmadiXato ⚙️ 503 🔄
2. ⭐ O'lchamlar:
Jami sinf: 22
Toifalar: 6
Aniq xatolar: 15
Maks chuqurlik: 3
5. ⭐ HTTP javoblar:
Istisno HTTP Ommaviy Xabar
──────────────────────────────────────────────────────────────────────────
ValidatsiyaXatosi 422 ✅ email: format noto'g'ri
UlanmadiXato 503 🔒 Ma'lumotlar bazasi xatosiNima ko'rsatdi: 2.2, 2.5, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Chuqur ierarxiya — professional" | 3 daraja yetadi |
| "Har xato uchun alohida sinf" | Atribut ko'pincha yaxshiroq |
| "Ierarxiyani keyin tuzataman" | Buzuvchi o'zgarish bo'ladi |
"IOError va OSError — boshqa" |
Bir xil (PEP 3151) |
| "Oraliq sinf qo'shish buzadi" | Xavfsiz — MRO kengayadi |
| "Ko'p meros — yomon" | Migratsiyada foydali |
| "Ierarxiyani test qilish ortiqcha" | Buzilishni tutadi |
"NotImplementedError — TypeError avlodi" |
RuntimeError avlodi |
6. Keng tarqalgan xatolar va yechimlari
1. Asos sinf yo'q
class XatoA(Exception): ... # ⚠️ tekis
class KutubxonaXatosi(Exception): ... # ✅2. Juda chuqur
A → B → C → D → E # ⚠️ 5 daraja
Asos → Toifa → Aniq # ✅ 3 daraja3. Sinf portlashi
class Xato400, Xato401, Xato403 ... # ⚠️
class HTTPXatosi(kod=403) # ✅ atribut4. Bo'sh oraliq sinf
class Oraliq(Asos): ... # ⚠️ 1 avlod
class Haqiqiy(Oraliq): ... # ✅ birlashtiring5. Asosni toraytirish
class X(TarmoqXatosi): ... # v1
class X(Exception): ... # ❌ v2 — buzadi6. Mantiqsiz meros
class VaqtTugadi(ValidatsiyaXatosi) # ⚠️ aloqasi yo'q
class VaqtTugadi(TarmoqXatosi) # ✅7. Docstring yo'q
class TarmoqXatosi(Asos): pass # ⚠️ nima uchun?
"""Tarmoq va tashqi xizmat.""" # ✅8. Ierarxiya testsiz
def test_asos():
assert issubclass(VaqtTugadi, KutubxonaXatosi) # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 9.6-dars (o'tilgan): o'z istisno sinflaringiz
- 9.8-dars: amaliy xatolar bilan ishlash
- 8-qism: meros, MRO,
ClassVar - 17-qism: ierarxiya testlari (
pytest) - 20-qism: HTTP xato kodlari
requests,httpx,sqlalchemy— namunali ierarxiyalar
8. Eng yaxshi amaliyotlar
Bitta asos sinfdan boshlang. Kengaytirish oson, torayish — buzuvchi.
Chuqurlikni 3 daraja bilan cheklang. Asos → Toifa → Aniq.
Toifa — har xil ishlov talab qilsa. Bir xil bo'lsa — kerak emas.
Atribut sinfdan ustun. "Alohida ushlanadimi?" — mezon.
Har sinfda docstring. Qachon ko'tariladi, nima qilish kerak.
Ierarxiyani testlar bilan muzlating.
issubclasstekshiruvlari.Faqat kengaytiring. Oraliq toifa qo'shish — xavfsiz.
Migratsiyada ko'p meros. Eski + yangi asos birga.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
1. print(issubclass(KeyError, LookupError))
2. print(issubclass(TimeoutError, OSError))
3. print(IOError is OSError, EnvironmentError is OSError)
4. print(type(OSError(2, "x")).__name__)
5. print(issubclass(NotImplementedError, RuntimeError))
6. print(issubclass(UnicodeDecodeError, ValueError))
7. print(issubclass(TabError, SyntaxError))
8. print(issubclass(KeyboardInterrupt, Exception))
9. print(issubclass(ModuleNotFoundError, ImportError))
10. print(len(FileNotFoundError.__mro__))
11. print(issubclass(ConnectionResetError, ConnectionError),
issubclass(ConnectionError, OSError))
12. print(issubclass(RecursionError, RuntimeError),
issubclass(MemoryError, Exception))Javoblar
TrueTrue— 3.3 danTrue True— PEP 3151FileNotFoundError—errnosehriTrue—RuntimeErroravlodiTrue—ValueError→UnicodeError→UnicodeDecodeErrorTrue—SyntaxError→IndentationError→TabErrorFalse—BaseExceptionavlodiTrue5—FileNotFoundError,OSError,Exception,BaseException,objectTrue TrueTrue True
Vazifa 2: Ierarxiyani tuzating
1. class XatoA(Exception): pass
class XatoB(Exception): pass
2. class A(Exception): pass
class B(A): pass
class C(B): pass
class D(C): pass
class E(D): pass
3. class Xato400(Asos), Xato401(Asos), ..., Xato503(Asos)
4. class Oraliq(Asos): pass
class Haqiqiy(Oraliq): pass
5. class VaqtTugadi(ValidatsiyaXatosi): pass
6. # v2.0 da:
class X(Exception): pass # oldin: class X(KutubxonaXatosi)
7. class TarmoqXatosi(Asos): pass # docstring yo'q
8. class X(TarmoqXatosi, MalumotXatosi): passJavoblar
1. Umumiy asos: class KutubxonaXatosi(Exception)
2. 3 darajaga qisqartiring: A → B → C
3. class HTTPXatosi(Asos) + kod atributi
4. Oraliq ni olib tashlang: class Haqiqiy(Asos)
5. class VaqtTugadi(TarmoqXatosi)
6. ❌ Buzuvchi — KutubxonaXatosi ni qaytaring
7. """Tarmoq va tashqi xizmat xatolari."""
8. Bitta toifa tanlang yoki yangi toifa yaratingVazifa 3: Ierarxiya loyihalang
Onlayn do'kon uchun:
- Bitta asos sinf
- 4-6 toifa (buyurtma, to'lov, yetkazish, ombor, ...)
- Har toifada 2-4 aniq xato
ClassVarsozlamalar (HTTP, qayta urinish, ommaviy)- Chuqurlik ≤ 3
- Har sinfda docstring
Vazifa 4: Ierarxiya tahlilchisi
Vosita yozing:
- Daraxtni chizsin (
__subclasses__) - Chuqurlik va kenglikni o'lchasin
- Bo'sh oraliq sinflarni topsin
- Docstringsizlarni topsin
- Mantiqsiz meroslarni bashorat qilsin
- Markdown hisobot chiqarsin
Vazifa 5: Migratsiya
Tekis ierarxiyani muvozanatliga aylantiring:
- Toifalarni aniqlang
- Oraliq sinflar qo'shing (buzmasdan)
- Eski nomlar uchun taxalluslar
DeprecationWarningqo'shing__all__ni yangilang- CHANGELOG yozing
Vazifa 6: Ierarxiya testlari
pytest testlari:
- Barcha sinflar asosdan meros
- Chuqurlik chegarasi
- Docstring mavjudligi
ClassVarqiymatlari to'g'ri- Bo'sh oraliq yo'qligi
str(e)bo'sh emasligi
Vazifa 7: O'ylash
Nega Python OSError oilasini errno tekshirishdan alohida sinflarga o'tkazdi (PEP 3151) — bu 10 yil kutildi?
Javob
Chunki errno bilan ishlash noqulay, platformaga bog'liq va xato bo'lishi oson edi — lekin tuzatish orqaga moslikni buzardi.
1. Eski holat — 6 ta sinf, bitta ma'no
Python 3.3 gacha:
IOError # fayl amallar
OSError # tizim chaqiruvlari
WindowsError # ⚠️ faqat Windows
EnvironmentError # ⚠️ IOError + OSError asosi
socket.error # ⚠️ tarmoq
select.error # ⚠️ select moduli
mmap.error # ⚠️ mmapMuammo: ular bir xil narsani anglatardi, lekin dasturchi qaysi birini ushlashni bilmasdi:
try:
f = open("fayl.txt")
except IOError: # ⚠️ yoki OSError?
...
try:
s.connect(...)
except socket.error: # ⚠️ IOError emas!
...Chegaralar tasodifiy edi:
open("yoq.txt") # IOError
os.remove("yoq.txt") # OSError ⚠️ nega boshqa?
os.stat("yoq.txt") # OSError2. errno tekshirish — asosiy og'riq
import errno
try:
with open(yol) as f:
...
except IOError as e:
if e.errno == errno.ENOENT:
print("Fayl yo'q")
elif e.errno == errno.EACCES:
print("Ruxsat yo'q")
elif e.errno == errno.EISDIR:
print("Bu papka")
else:
raiseMuammolar:
- Batafsil — 3 qatorlik ish 8 qator
import errnokerak- Konstanta nomlari —
ENOENT?ENOTDIR? Eslash qiyin else: raiseunutiladi → xatolar yutiladi- Platformaga bog'liq — Windows da boshqa kodlar
3. Windows muammosi
# Unix
e.errno == errno.ENOENT # 2
# Windows
e.errno == errno.ENOENT # ba'zan
e.winerror == 2 # ⚠️ ba'zan boshqa kod WindowsError — faqat Windows da mavjud:
try:
...
except WindowsError: # ❌ Linux da NameError!
...Shuning uchun kross-platforma kod yozish juda qiyin edi.
4. PEP 3151 (2011) — Antoine Pitrou
Taklif:
OSError ⭐ YAGONA asos
├── BlockingIOError EAGAIN, EALREADY, EWOULDBLOCK, EINPROGRESS
├── ChildProcessError ECHILD
├── ConnectionError ⭐ ichki guruh
│ ├── BrokenPipeError EPIPE, ESHUTDOWN
│ ├── ConnectionAbortedError ECONNABORTED
│ ├── ConnectionRefusedError ECONNREFUSED
│ └── ConnectionResetError ECONNRESET
├── FileExistsError EEXIST
├── FileNotFoundError ENOENT
├── InterruptedError EINTR
├── IsADirectoryError EISDIR
├── NotADirectoryError ENOTDIR
├── PermissionError EACCES, EPERM
├── ProcessLookupError ESRCH
└── TimeoutError ETIMEDOUTBarcha eski nomlar taxallusga aylandi:
IOError = OSError
EnvironmentError = OSError
WindowsError = OSError # (faqat Windows da)
socket.error = OSError
select.error = OSError
mmap.error = OSError5. __new__ sehri — orqaga moslik kaliti
Eng aqlli qism:
class OSError(Exception):
def __new__(cls, *args):
if cls is OSError and len(args) >= 2:
errno_ = args[0]
yangi = _ERRNO_XARITA.get(errno_)
if yangi is not None:
cls = yangi # ⭐ AVLODNI ALMASHTIRADI
return super().__new__(cls, *args)Natija:
OSError(2, "Fayl yo'q") # → FileNotFoundError
OSError(13, "Ruxsat") # → PermissionErrorNega bu muhim:
Minglab kutubxonalar OSError(errno, msg) yozgan edi. Ular hech narsa o'zgartirmasdan yangi avlodlarni ko'tara boshladi.
# Eski kutubxona kodi (o'zgarmagan):
raise OSError(errno.ENOENT, "Konfiguratsiya topilmadi")
# Yangi foydalanuvchi kodi:
except FileNotFoundError: # ⭐ ISHLAYDI!6. Nega 10 yil kutildi
a) Orqaga moslik qo'rquvi
# ⚠️ Bu kod buziladimi?
except IOError:
... Javob: yo'q — IOError OSError ga taxallus, va yangi sinflar uning avlodlari.
b) Python 2 → 3 o'tish davri
2008-2011 da hamma Python 3 ga o'tish bilan band edi. Yana bir buzuvchi o'zgarish — juda ko'p.
c) Qaysi errno qaysi sinfga
Munozara uzoq davom etdi:
EACCES va EPERM — bitta sinfmi? → ha, PermissionError
EAGAIN, EWOULDBLOCK — bir xilmi? → ha, BlockingIOError
ENOTDIR — alohida sinf kerakmi? → ha
EROFS (read-only fs) — kerakmi? → yo'q, kam ishlatiladiMezon: "bu xatoni alohida ushlash kerakmi?" — 9.6-darsdagi qoida.
d) Sinflar sonini cheklash
errno da 130+ konstanta bor. Hammasiga sinf yaratish — antipattern (sinf portlashi).
Tanlangan: eng ko'p ishlatiladigan 15 tasi. Qolganlar — oddiy OSError + errno.
7. Natija — kod qanchalik soddalashdi
Oldin:
import errno
try:
ish()
except IOError as e:
if e.errno in (errno.EACCES, errno.EPERM):
ruxsat_sora()
elif e.errno == errno.ENOENT:
yarat()
elif e.errno == errno.EEXIST:
pass
else:
raise
except OSError as e: # ⚠️ takror!
if e.errno == errno.ENOENT:
...
else:
raiseKeyin:
try:
ish()
except PermissionError:
ruxsat_sora()
except FileNotFoundError:
yarat()
except FileExistsError:
pass 17 qator → 7 qator, va import errno kerak emas.
8. Bundan o'rganish
| Dars | Tushuntirish |
|---|---|
| Atribut tekshirish — antipattern | if e.errno == X → alohida sinflar |
| Cheklangan sinflar | 130 dan 15 tasi tanlandi |
| Guruhlash | ConnectionError — 4 ta ostida |
| Taxallus bilan migratsiya | IOError = OSError |
__new__ bilan avtomatik |
Eski kod yangi sinflarni ko'taradi |
| Kengaytirish, toraytirmaslik | Barcha eski except ishlaydi |
Sizning kutubxonangiz uchun:
# ⚠️ Agar shunday yozgan bo'lsangiz:
class APIXatosi(Exception):
def __init__(self, kod): self.kod = kod
except APIXatosi as e:
if e.kod == 404: ... # ⚠️ errno naqshi!
elif e.kod == 403: ...
# ✅ Ehtimol shunday bo'lishi kerak:
class APIXatosi(Exception): ...
class TopilmadiXatosi(APIXatosi): ...
class RuxsatYoqXatosi(APIXatosi): ...
# ⭐ Va __new__ bilan orqaga moslik:
class APIXatosi(Exception):
def __new__(cls, kod=0, *args):
if cls is APIXatosi:
cls = _XARITA.get(kod, cls)
return super().__new__(cls, kod, *args)9. Nima yakunlanmadi
issubclass(TimeoutError, OSError) # True
# ⚠️ Lekin 3.10 gacha:
import asyncio, socket, concurrent.futures
asyncio.TimeoutError is not TimeoutError # ⚠️ boshqa!
socket.timeout is not TimeoutError # ⚠️ boshqa!3.11 da tuzatildi:
socket.timeout is TimeoutError # True
asyncio.TimeoutError is TimeoutError # True
concurrent.futures.TimeoutError is TimeoutError # True Ya'ni OSError birlashtirilganidan 8 yil keyin TimeoutError birlashtirildi. Ierarxiya tozalash — sekin jarayon.
10. Xulosa
errnotekshirish — batafsil, xatoga moyil, platformaga bog'liq- PEP 3151 (3.3, 2012) — 15 ta aniq sinf, 6 ta eski nom taxallusga
OSError.__new__errnoga qarab avlodni tanlaydi — orqaga moslik- 10 yil kutildi — orqaga moslik qo'rquvi va Python 3 o'tish davri
- Dars: atributga qarab shoxlanish (
if e.kod == X) — ierarxiya kerakligi belgisi
Amaliy qoida:
if e.kod == X: ... # ⚠️ 3+ marta bo'lsa — sinf yarating
except AniqXato: ... # ✅Nimani mustahkamlaydi: 2.1, 2.2, 2.4, 2.6-bo'limlar.
Xulosa
Bu darsda istisnolar ierarxiyasini loyihalashni o'rgandik.
Eng muhim uch fikr:
Uch daraja yetadi: Asos → Toifa → Aniq xato. Bitta asos sinf — foydalanuvchi hammasini ushlashi uchun; 2-6 toifa — har biri har xil ishlov talab qilsa; aniq xatolar — atributlar bilan. Chuqurroq ierarxiya (
httpxdagi 4 daraja) — istisno, qoida emas.Atribut sinfdan ustun — mezon "alohida ushlanadimi?". 20 ta
Xato400,Xato401o'rniga bittaHTTPXatosi(kod=...). Aksincha ham to'g'ri:if e.errno == Xnaqshi uch marta takrorlansa — bu sinf kerakligi belgisi (PEP 3151 aynan shuni tuzatdi).Ierarxiyani faqat kengaytiring. Oraliq toifa qo'shish xavfsiz — MRO kengayadi, eski
exceptbloklar ishlashda davom etadi. Asosni toraytirish (class X(TarmoqXatosi)→class X(Exception)) — buzuvchi o'zgarish, major versiya kerak. Migratsiyada ko'p meros vaDeprecationWarningyordam beradi,issubclasstestlari esa ierarxiyani muzlatadi.
Keyingi darsda 9-qismni yakunlaymiz: xatolar bilan ishlashning amaliy jihatlari — jurnal, monitoring, foydalanuvchi xabarlari va butun tizim darajasidagi strategiya.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!