Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. To'liq sintaksis
- 2.2. else — nega kerak
- 2.3. finally — har doim
- 2.4. finally va return to'qnashuvi
- 2.5. finally va o'zgaruvchilar
- 2.6. Tozalash naqshlari
- 2.7. Amaliy naqshlar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Bajarilish tartibi
- Misol 2 — Tozalash naqshlari
- Misol 3 — with va kontekst menejerlari
- Misol 4 — Amaliy: ishonchli quvur
- 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.3-dars: else va finally
9-QISM — XATOLAR VA ISTISNOLAR · 3-dars
1. Kirish va motivatsiya
Bu kod xato beradi — lekin xato try da emas:
try:
m = json.loads(matn)
ishla(m) # ⚠️ bu ham try ichida
except json.JSONDecodeError:
jurnal.error("JSON buzilgan") Agar ishla() ichida ValueError chiqsa va u JSONDecodeError bo'lsa — noto'g'ri xabar yoziladi.
else bilan:
try:
m = json.loads(matn) # ⭐ FAQAT xavfli qism
except json.JSONDecodeError:
jurnal.error("JSON buzilgan")
else:
ishla(m) # ⭐ xato bo'lmagandaVa bu — chalkash:
def f():
try:
return 1
finally:
return 2
f() # ⚠️ 2 — birinchi return YO'QOLDIBu darsda:
-
else— qachon va nega -
finally— har doim bajariladi -
finallyvareturn/break/continueto'qnashuvi - To'liq bajarilish tartibi (8 holat)
finallyva istisno "yutilishi"-
with—try/finallyning yaxshi muqobili
2. Nazariya — chuqur tushuntirish
2.1. To'liq sintaksis
try:
... # xavfli kod
except Xato1:
... # xato bo'lsa
except Xato2:
...
else:
... # ⭐ xato BO'LMASA
finally:
... # ⭐ HAR DOIMBajarilish tartibi:
| Holat | try |
except |
else |
finally |
|---|---|---|---|---|
| Xato yo'q | to'liq | |||
| Xato ushlandi | qisman | |||
| Xato ushlanmadi | qisman | → keyin ko'tariladi | ||
try da return |
qisman | → keyin qaytadi | ||
except da return |
→ keyin qaytadi | |||
try da break |
→ keyin chiqadi |
finally — har doim, istisnosiz.
Cheklovlar:
try:
...
else: # ❌ SyntaxError
... else — faqat except bilan birga.
try:
...
finally:
... # ✅ except siz mumkin2.2. else — nega kerak
Muammo: try bloki juda keng
try:
m = json.loads(matn) # ⚠️ bu xato berishi mumkin
n = ishla(m) # ⚠️ bu ham
saqla(n) # ⚠️ bu ham
except ValueError:
jurnal.error("JSON buzilgan") # ⚠️ lekin qaysi biri? else bilan aniq:
try:
m = json.loads(matn) # ⭐ FAQAT bu himoyalangan
except json.JSONDecodeError:
jurnal.error("JSON buzilgan")
else:
n = ishla(m) # ⭐ bu yerdagi xato UZATILADI
saqla(n)Uch foyda:
- Aniqlik — qaysi qator himoyalangani ko'rinadi
- Xato yashirilmaydi —
elsedagi xatoexceptga tushmaydi - Niyat — "bu faqat muvaffaqiyatda bajariladi"
else va return:
def f():
try:
q = ol()
except KeyError:
return None
else:
return ishla(q) # ⭐ aniqroq
# yoki shunchaki:
return ishla(q) # ✅ ham to'g'ri (except return qiladi) except da return/raise bo'lsa — else ixtiyoriy.
2.3. finally — har doim
f = open(yol)
try:
ishla(f)
finally:
f.close() # ⭐ xato bo'lsa ham yopiladi finally bajariladi:
- Xato bo'lmasa
- Xato ushlansa
- Xato ushlanmasa (keyin ko'tariladi)
returnbo'lsa (keyin qaytadi)break/continuebo'lsasys.exit()bo'lsa (SystemExit— istisno)
Bajarilmaydi:
os._exit()— jarayonni darhol o'ldiradi- Segfault, elektr o'chishi
- Cheksiz tsikl
tryichida -
KeyboardInterruptjuda noto'g'ri vaqtda (kamdan-kam)
2.4. finally va return to'qnashuvi
def f():
try:
return 1 # ⚠️ qiymat HISOBLANADI
finally:
return 2 # ⚠️ lekin BU qaytadi
f() # 2Mexanizm:
trydareturn 1— qiymat (1) saqlanadifinallybajariladifinallydareturn 2— yangi qiymat- Birinchisi yo'qoladi
Istisno ham yutiladi:
def f():
try:
raise ValueError("xato")
finally:
return "OK" # ⚠️ istisno YO'QOLDI
f() # 'OK' — xato yo'q! break/continue ham:
for i in range(3):
try:
break
finally:
continue # ⚠️ break bekor qilindi
# → cheksiz tsikl Qoida: finally da return, break, continue yozmang.
Python 3.8+ da finally ichidagi continue ruxsat; 3.7 gacha SyntaxError edi.
2.5. finally va o'zgaruvchilar
def f():
try:
x = 1
return x # ⭐ qiymat saqlanadi (1)
finally:
x = 2 # ⚠️ kech — qiymat allaqachon olingan
f() # 1 Sabab: return x — x ning qiymati olinadi, keyin finally.
O'zgaruvchan obyektlar boshqacha:
def f():
try:
lst = [1]
return lst # ⭐ HAVOLA saqlanadi
finally:
lst.append(2) # ⚠️ o'sha obyekt o'zgardi
f() # [1, 2]2.6. Tozalash naqshlari
A) try/finally — asosiy:
r = ochish()
try:
ishla(r)
finally:
r.yop() B) with — yaxshiroq:
with ochish() as r:
ishla(r) # ✅ avtomatik yopiladiC) Bir nechta resurs:
# ⚠️ Ichma-ich
a = ochish("a")
try:
b = ochish("b")
try:
ishla(a, b)
finally:
b.yop()
finally:
a.yop()
# ✅ with bilan
with ochish("a") as a, ochish("b") as b:
ishla(a, b)D) contextlib.ExitStack — dinamik:
from contextlib import ExitStack
with ExitStack() as stack:
fayllar = [stack.enter_context(open(y)) for y in yollar]
ishla(fayllar) # ✅ hammasi yopiladi2.7. Amaliy naqshlar
Vaqt o'lchash:
boshlanish = time.perf_counter()
try:
ish()
finally:
vaqt = time.perf_counter() - boshlanish # ⭐ xato bo'lsa ham
jurnal.info("Vaqt: %.3fs", vaqt)Holat qaytarish:
eski = sozlama.qiymat
sozlama.qiymat = yangi
try:
ish()
finally:
sozlama.qiymat = eski # ⭐ har doim qaytariladiQulf:
qulf.acquire()
try:
kritik_bolim()
finally:
qulf.release() # ⭐ deadlock bo'lmaydi
# yoki: with qulf:Tranzaksiya:
tranzaksiya.boshla()
try:
amallar()
except Exception:
tranzaksiya.bekor()
raise
else:
tranzaksiya.tasdiqla()
finally:
ulanish.yop()3. Tez ma'lumotnoma
To'liq sintaksis
try:
... xavfli kod
except X:
... xato bo'lsa
else:
... ⭐ xato BO'LMASA (except bilan birga)
finally:
... ⭐ HAR DOIMBajarilish jadvali
try except else finally
Xato yo'q ✅ ❌ ✅ ✅
Ushlandi ⚠️ ✅ ❌ ✅
Ushlanmadi ⚠️ ❌ ❌ ✅ → ko'tariladi
return ⚠️ — ❌ ✅ → qaytadi
break ⚠️ — ❌ ✅ → chiqadifinally tuzoqlari
try: return 1
finally: return 2 → 2 (birinchisi yo'qoldi)
try: raise X()
finally: return 1 → 1 (istisno YUTILDI)
for: try: break
finally: continue → cheksiz tsikl
⭐ QOIDA: finally da return/break/continue YOZMANGMuqobillar
try/finally asosiy
with ✅ yaxshiroq
ExitStack dinamik ko'p resurs
contextlib.suppress ataylab yutish4. Batafsil misollar
Misol 1 — Bajarilish tartibi
"""else va finally qachon bajariladi."""
import sys
print("=== ⭐ 1. To'liq jadval ===\n")
def kuzatuv(holat: str) -> tuple[list[str], object]:
"""Barcha holatlarda nima bajarilishini kuzatadi."""
izlar = []
def ish():
try:
izlar.append("try boshi")
if holat == "xato_ushlanadi":
raise ValueError("ushlanadi")
if holat == "xato_ushlanmaydi":
raise TypeError("ushlanmaydi")
if holat == "try_return":
izlar.append("try: return")
return "try dan"
izlar.append("try oxiri")
except ValueError:
izlar.append("except")
if holat == "except_return":
izlar.append("except: return")
return "except dan"
else:
izlar.append("else")
if holat == "else_return":
izlar.append("else: return")
return "else dan"
finally:
izlar.append("finally")
izlar.append("funksiya oxiri")
return "oxirdan"
try:
natija = ish()
except Exception as e:
natija = f"❌ {type(e).__name__}"
return izlar, natija
HOLATLAR = [
("Xato yo'q", "xatosiz"),
("Xato ushlandi", "xato_ushlanadi"),
("Xato ushlanmadi", "xato_ushlanmaydi"),
("try da return", "try_return"),
("except da return", "except_return"),
("else da return", "else_return"),
]
print(f" {'Holat':<22} {'Bajarilish':<44} {'Natija'}")
print(" " + "─" * 78)
for nom, kod in HOLATLAR:
izlar, natija = kuzatuv(kod)
yol = " → ".join(izlar)
print(f" {nom:<22} {yol[:42]:<44} {natija}")
print(f"""
⭐ KUZATUVLAR:
1. finally — BARCHA holatlarda bajarildi
2. else — faqat xato BO'LMAGANDA
3. Xato ushlanmasa — finally bajarilib, keyin ko'tariladi
4. return bo'lsa — finally bajarilib, keyin qaytadi
""")
print("=== 2. else nima uchun kerak ===\n")
import json
def yomon(matn: str) -> str:
"""⚠️ try bloki JUDA KENG."""
try:
m = json.loads(matn)
n = m["natija"] * 2 # ⚠️ bu ham try ichida
return f"✅ {n}"
except (json.JSONDecodeError, ValueError):
return "❌ JSON buzilgan" # ⚠️ noto'g'ri xabar!
def yaxshi(matn: str) -> str:
"""✅ Faqat xavfli qism himoyalangan."""
try:
m = json.loads(matn)
except json.JSONDecodeError:
return "❌ JSON buzilgan"
else:
n = m["natija"] * 2 # ⭐ bu yerdagi xato UZATILADI
return f"✅ {n}"
SINOVLAR = [
('{"natija": 21}', "to'g'ri"),
("{buzilgan}", "JSON xatosi"),
('{"natija": "matn"}', "TypeError kutiladi"),
('{"boshqa": 1}', "KeyError kutiladi"),
]
print(f" {'Kirish':<22} {'Yomon (keng try)':<26} {'Yaxshi (else)'}")
print(" " + "─" * 74)
for matn, tavsif in SINOVLAR:
try:
r1 = yomon(matn)
except Exception as e:
r1 = f"❌ {type(e).__name__}"
try:
r2 = yaxshi(matn)
except Exception as e:
r2 = f"❌ {type(e).__name__}"
belgi = "⚠️" if r1 != r2 else ""
print(f" {matn:<22} {r1:<26} {r2} {belgi}")
print(f"""
⚠️ YOMON versiyada:
'{{"natija": "matn"}}' → "JSON buzilgan" ❌ NOTO'G'RI
(aslida TypeError — "matn" * 2 emas, "matnmatn")
'{{"boshqa": 1}}' → KeyError UZATILDI ⚠️ tasodifan to'g'ri
✅ YAXSHI versiyada:
Har xato O'Z JOYIDA aniqlanadi
""")
print("=== ⚠️ 3. finally va return ===\n")
def f1():
try:
return 1
finally:
pass
def f2():
try:
return 1
finally:
return 2 # ⚠️
def f3():
try:
raise ValueError("xato")
finally:
return "OK" # ⚠️ istisno yutildi
def f4():
try:
x = 1
return x
finally:
x = 2 # ⚠️ kech
def f5():
try:
lst = [1]
return lst
finally:
lst.append(2) # ⚠️ o'zgaruvchan!
def f6():
try:
return [1]
finally:
pass
FUNKSIYALAR = [
("try: return 1 / finally: pass", f1, "1"),
("try: return 1 / finally: return 2", f2, "⚠️ 2"),
("try: raise / finally: return 'OK'", f3, "⚠️ 'OK' (xato yutildi)"),
("try: return x / finally: x = 2", f4, "1 (qiymat saqlangan)"),
("try: return lst / finally: append", f5, "⚠️ [1,2] (havola!)"),
("try: return [1] / finally: pass", f6, "[1]"),
]
print(f" {'Kod':<40} {'Natija':<18} {'Izoh'}")
print(" " + "─" * 78)
for kod, f, izoh in FUNKSIYALAR:
try:
n = repr(f())
except Exception as e:
n = f"❌ {type(e).__name__}"
print(f" {kod:<40} {n:<18} {izoh}")
print(f"""
⭐ MEXANIZM (return + finally):
1. try da `return x` → x ning QIYMATI hisoblanadi va saqlanadi
2. finally bajariladi
3a. finally da return YO'Q → saqlangan qiymat qaytadi
3b. finally da return BOR → ⚠️ YANGI qiymat, eskisi yo'qoladi
⚠️ O'ZGARUVCHAN obyektlar:
`return lst` — HAVOLA saqlanadi
finally da lst.append(2) → o'sha obyekt o'zgaradi
→ [1, 2] qaytadi
""")
print("=== ⚠️ 4. finally va break/continue ===\n")
def break_finally():
izlar = []
for i in range(3):
try:
izlar.append(f"try {i}")
break
finally:
izlar.append(f"finally {i}")
izlar.append("tsikldan keyin")
return izlar
def continue_finally():
izlar = []
for i in range(3):
try:
izlar.append(f"try {i}")
if i == 1:
continue
izlar.append(f"davom {i}")
finally:
izlar.append(f"finally {i}")
return izlar
def break_bekor():
"""⚠️ finally da continue break ni bekor qiladi."""
izlar = []
hisoblagich = 0
for i in range(3):
hisoblagich += 1
if hisoblagich > 5: # xavfsizlik
izlar.append("⚠️ TO'XTATILDI (cheksiz tsikl)")
break
try:
izlar.append(f"try {i}: break")
break
finally:
izlar.append(f"finally {i}: continue")
continue # ⚠️ break bekor qilindi
return izlar
print(f" break + finally:")
for q in break_finally():
print(f" {q}")
print(f"\n continue + finally:")
for q in continue_finally():
print(f" {q}")
if sys.version_info >= (3, 8):
print(f"\n ⚠️ finally da continue (break ni bekor qiladi):")
for q in break_bekor():
print(f" {q}")
else:
print(f"\n ⚠️ finally da continue — 3.8 dan oldin SyntaxError")
print(f"""
⭐ QOIDA:
finally da return, break, continue YOZMANG.
Sabab: ular try/except dagi nazorat oqimini
JIMGINA bekor qiladi.
✅ finally FAQAT tozalash uchun:
yopish, bo'shatish, jurnalga yozish, holatni qaytarish
""")
print("=== 5. Istisno bilan finally ===\n")
def izlar_bilan(xato: bool, finally_xato: bool):
izlar = []
try:
try:
izlar.append("try")
if xato:
raise ValueError("try dan")
finally:
izlar.append("finally")
if finally_xato:
raise TypeError("finally dan") # ⚠️
except Exception as e:
izlar.append(f"ushlandi: {type(e).__name__}: {e}")
if e.__context__:
izlar.append(f" kontekst: {type(e.__context__).__name__}")
return izlar
HOLATLAR2 = [
("Xato yo'q", False, False),
("try da xato", True, False),
("finally da xato", False, True),
("Ikkalasida ham xato", True, True),
]
for nom, x1, x2 in HOLATLAR2:
print(f" {nom}:")
for q in izlar_bilan(x1, x2):
print(f" {q}")
print()
print(f""" ⚠️ finally DA XATO — try dagi xatoni ALMASHTIRADI!
Asl xato __context__ da saqlanadi, lekin
ko'tariladigan istisno — finally dagisi.
✅ finally ni XAVFSIZ qiling:
finally:
try:
r.yop()
except Exception:
jurnal.exception("Yopishda xato")
""")Natijaning muhim qismi:
=== ⭐ 1. To'liq jadval ===
Holat Bajarilish Natija
──────────────────────────────────────────────────────────────────────────
Xato yo'q try boshi → try oxiri → else → finally → f oxirdan
Xato ushlandi try boshi → except → finally → funksiya ox oxirdan
Xato ushlanmadi try boshi → finally ❌ TypeError
try da return try boshi → try: return → finally try dan
else da return try boshi → try oxiri → else → else: retur else dan
=== 2. else nima uchun kerak ===
Kirish Yomon (keng try) Yaxshi (else)
──────────────────────────────────────────────────────────────────────────
{"natija": 21} ✅ 42 ✅ 42
{buzilgan} ❌ JSON buzilgan ❌ JSON buzilgan
{"natija": "matn"} ✅ matnmatn ✅ matnmatn
{"boshqa": 1} ❌ KeyError ❌ KeyError
=== ⚠️ 3. finally va return ===
try: return 1 / finally: return 2 2 ⚠️ 2
try: raise / finally: return 'OK' 'OK' ⚠️ 'OK' (xato yutildi)
try: return lst / finally: append [1, 2] ⚠️ [1,2] (havola!)Nima ko'rsatdi: 2.1, 2.2, 2.4, 2.5-bo'limlar.
Misol 2 — Tozalash naqshlari
"""finally va with bilan resurslarni boshqarish."""
from __future__ import annotations
import contextlib
import io
import tempfile
import threading
import time
from pathlib import Path
print("=== 1. Resurs yopish ===\n")
class Resurs:
"""Kuzatiladigan resurs."""
JURNAL: list[str] = []
def __init__(self, nom: str, ochishda_xato: bool = False,
yopishda_xato: bool = False):
self.nom = nom
self.yopilgan = False
self._yopishda_xato = yopishda_xato
if ochishda_xato:
raise OSError(f"{nom} ochilmadi")
Resurs.JURNAL.append(f"+ {nom} ochildi")
def ishla(self, xato: bool = False):
if self.yopilgan:
raise ValueError(f"{self.nom} yopilgan")
if xato:
raise RuntimeError(f"{self.nom} da xato")
return f"{self.nom} ishladi"
def yop(self):
if self._yopishda_xato:
raise OSError(f"{self.nom} yopilmadi")
self.yopilgan = True
Resurs.JURNAL.append(f"- {self.nom} yopildi")
def __enter__(self):
return self
def __exit__(self, *_):
self.yop()
return False
def yopishsiz(xato: bool):
"""⚠️ Xato bo'lsa yopilmaydi."""
r = Resurs("A")
r.ishla(xato)
r.yop() # ⚠️ bajarilmasligi mumkin
return "OK"
def finally_bilan(xato: bool):
"""✅ Har doim yopiladi."""
r = Resurs("B")
try:
r.ishla(xato)
return "OK"
finally:
r.yop() # ⭐ HAR DOIM
def with_bilan(xato: bool):
"""✅ Eng oddiy."""
with Resurs("C") as r:
r.ishla(xato)
return "OK"
print(f" {'Usul':<18} {'Xatosiz':<12} {'Xato bilan':<20} "
f"{'Yopildimi'}")
print(" " + "─" * 66)
for nom, f in [("Yopishsiz", yopishsiz), ("finally", finally_bilan),
("with", with_bilan)]:
Resurs.JURNAL.clear()
try:
r1 = f(False)
except Exception as e:
r1 = f"❌ {type(e).__name__}"
yopildi1 = sum(1 for j in Resurs.JURNAL if j.startswith("-"))
Resurs.JURNAL.clear()
try:
r2 = f(True)
except Exception as e:
r2 = f"❌ {type(e).__name__}"
yopildi2 = sum(1 for j in Resurs.JURNAL if j.startswith("-"))
belgi = "✅" if yopildi2 else "⚠️ YO'Q"
print(f" {nom:<18} {r1:<12} {r2:<20} {belgi}")
print(f"""
⚠️ Yopishsiz: xato bo'lsa r.yop() BAJARILMAYDI
→ resurs oqishi (fayl deskriptori, ulanish, qulf)
✅ finally / with: har doim yopiladi
""")
print("=== 2. Bir nechta resurs ===\n")
def ichma_ich():
"""⚠️ Uch resurs — uch daraja."""
a = Resurs("A")
try:
b = Resurs("B")
try:
c = Resurs("C")
try:
return "hammasi ishladi"
finally:
c.yop()
finally:
b.yop()
finally:
a.yop()
def with_kop():
"""✅ Bitta with."""
with Resurs("A") as a, Resurs("B") as b, Resurs("C") as c:
return "hammasi ishladi"
def exitstack_bilan(nomlar: list[str]):
"""⭐ DINAMIK son."""
with contextlib.ExitStack() as stack:
resurslar = [stack.enter_context(Resurs(n)) for n in nomlar]
return f"{len(resurslar)} resurs"
for nom, f in [("Ichma-ich", ichma_ich), ("with (ko'p)", with_kop)]:
Resurs.JURNAL.clear()
natija = f()
print(f" {nom}:")
print(f" {natija}")
print(f" Jurnal: {' '.join(Resurs.JURNAL)}")
Resurs.JURNAL.clear()
print(f"\n ExitStack (dinamik):")
print(f" {exitstack_bilan(['X', 'Y', 'Z', 'W'])}")
print(f" Jurnal: {' '.join(Resurs.JURNAL)}")
print(f"""
⭐ YOPISH TARTIBI: TESKARI (LIFO)
Ochildi: A → B → C
Yopildi: C → B → A
⭐ ExitStack — resurslar soni ish vaqtida ma'lum bo'lsa
""")
print("=== ⚠️ 3. Ochishda xato ===\n")
def ochishda_xato_yomon():
"""⚠️ B ochilmasa, A yopilmaydi."""
a = Resurs("A")
b = Resurs("B", ochishda_xato=True) # ❌
try:
return "OK"
finally:
b.yop()
a.yop()
def ochishda_xato_yaxshi():
"""✅ Har biri o'z try da."""
a = Resurs("A")
try:
b = Resurs("B", ochishda_xato=True)
try:
return "OK"
finally:
b.yop()
finally:
a.yop()
def with_ochishda_xato():
"""✅ with o'zi hal qiladi."""
with Resurs("A") as a:
with Resurs("B", ochishda_xato=True) as b:
return "OK"
for nom, f in [("Yomon", ochishda_xato_yomon),
("Yaxshi (ichma-ich)", ochishda_xato_yaxshi),
("with", with_ochishda_xato)]:
Resurs.JURNAL.clear()
try:
f()
n = "✅"
except OSError as e:
n = f"❌ {e}"
yopildi = [j for j in Resurs.JURNAL if j.startswith("-")]
print(f" {nom:<22} {n:<20} yopildi: {yopildi or '⚠️ HECH NARSA'}")
print(f"""
⭐ QOIDA: resursni ochgandan KEYIN darhol try boshlang.
❌ a = ochish(); b = ochish(); try: ...
✅ a = ochish(); try: b = ochish(); try: ...
✅ with ochish() as a, ochish() as b: ...
""")
print("=== ⚠️ 4. Yopishda xato ===\n")
def yopishda_xato(asl_xato: bool):
r = Resurs("A", yopishda_xato=True)
try:
r.ishla(asl_xato)
return "OK"
finally:
r.yop() # ⚠️ bu ham xato beradi
for asl in [False, True]:
try:
yopishda_xato(asl)
n = "✅ OK"
except Exception as e:
ctx = (f" (kontekst: {type(e.__context__).__name__})"
if e.__context__ else "")
n = f"❌ {type(e).__name__}: {e}{ctx}"
print(f" Asl xato={asl!s:<6} → {n}")
print(f"\n ✅ Xavfsiz yopish:")
def xavfsiz_yopish(asl_xato: bool):
r = Resurs("A", yopishda_xato=True)
try:
r.ishla(asl_xato)
return "OK"
finally:
try:
r.yop()
except Exception as e: # ⭐ yopish xatosi yutiladi
print(f" ⚠️ Yopishda xato (jurnal): {e}")
for asl in [False, True]:
try:
n = f"✅ {xavfsiz_yopish(asl)}"
except Exception as e:
n = f"❌ {type(e).__name__}: {e}" # ⭐ ASL xato
print(f" Asl xato={asl!s:<6} → {n}")
print(f"""
⚠️ finally DA XATO asl xatoni ALMASHTIRADI.
Foydalanuvchi haqiqiy sababni ko'rmaydi.
✅ Yopish xatosini yutib, JURNALGA yozing.
""")
print("=== ⭐ 5. Amaliy naqshlar ===\n")
print(" A) Vaqt o'lchash:\n")
def olchov(f, *args):
boshlanish = time.perf_counter()
try:
return f(*args)
finally: # ⭐ xato bo'lsa ham
vaqt = (time.perf_counter() - boshlanish) * 1000
print(f" ⏱ {f.__name__}: {vaqt:.2f}ms")
def tez(): time.sleep(0.001); return "tez"
def sekin(): time.sleep(0.01); return "sekin"
def xatoli(): time.sleep(0.005); raise ValueError("xato")
for f in (tez, sekin, xatoli):
try:
n = olchov(f)
print(f" {f.__name__}: {n}")
except ValueError as e:
print(f" {f.__name__}: ❌ {e} ⭐ vaqt baribir o'lchandi")
print(f"\n B) Holatni qaytarish:\n")
SOZLAMA = {"debug": False, "chegara": 100}
def vaqtincha_ozgartir(xato: bool):
eski = SOZLAMA.copy()
SOZLAMA["debug"] = True
SOZLAMA["chegara"] = 999
try:
print(f" Ichkarida: {SOZLAMA}")
if xato:
raise RuntimeError("xato")
return "OK"
finally:
SOZLAMA.clear()
SOZLAMA.update(eski) # ⭐ qaytarildi
for xato in [False, True]:
print(f" Xato={xato}:")
try:
vaqtincha_ozgartir(xato)
except RuntimeError:
pass
print(f" Keyin: {SOZLAMA} ✅ qaytarildi")
print(f"\n C) Qulf:\n")
qulf = threading.Lock()
hisob = {"qiymat": 0}
def qulfsiz(xato: bool):
"""⚠️ Xato bo'lsa qulf ochilmaydi."""
qulf.acquire()
if xato:
raise ValueError("xato")
hisob["qiymat"] += 1
qulf.release() # ⚠️ bajarilmaydi
def qulf_finally(xato: bool):
qulf.acquire()
try:
if xato:
raise ValueError("xato")
hisob["qiymat"] += 1
finally:
qulf.release() # ⭐ HAR DOIM
def qulf_with(xato: bool):
with qulf: # ✅ eng oddiy
if xato:
raise ValueError("xato")
hisob["qiymat"] += 1
for nom, f in [("finally", qulf_finally), ("with", qulf_with)]:
try:
f(True)
except ValueError:
pass
ochiq = not qulf.locked()
print(f" {nom:<12} xatodan keyin qulf ochiq: "
f"{'✅' if ochiq else '⚠️ YO`Q — DEADLOCK'}")
print(f"\n D) Tranzaksiya:\n")
class Tranzaksiya:
def __init__(self):
self.amallar: list[str] = []
self.holat = "yangi"
self.yopilgan = False
def boshla(self):
self.holat = "ochiq"
self.amallar.append("BEGIN")
def bajar(self, sql: str, xato: bool = False):
if xato:
raise RuntimeError(f"SQL xatosi: {sql}")
self.amallar.append(sql)
def tasdiqla(self):
self.holat = "tasdiqlangan"
self.amallar.append("COMMIT")
def bekor(self):
self.holat = "bekor"
self.amallar.append("ROLLBACK")
def yop(self):
self.yopilgan = True
def tranzaksiya_ishi(xato: bool):
"""⭐ except + else + finally birga."""
t = Tranzaksiya()
t.boshla()
try:
t.bajar("INSERT INTO xodimlar ...")
t.bajar("UPDATE hisoblar ...", xato)
except Exception:
t.bekor() # ⭐ xato bo'lsa
raise
else:
t.tasdiqla() # ⭐ xato bo'lmasa
finally:
t.yop() # ⭐ har doim
return t
for xato in [False, True]:
print(f" Xato={xato}:")
try:
t = tranzaksiya_ishi(xato)
except RuntimeError as e:
print(f" ❌ {e}")
t = None
if t is None:
print(f" (tranzaksiya bekor qilindi)")
else:
print(f" Holat: {t.holat}")
print(f" Amallar: {' | '.join(t.amallar)}")
print(f"""
⭐ TRANZAKSIYA NAQSHI:
try: amallar
except: bekor() + raise
else: tasdiqla()
finally: yop()
⭐ Bu — else va finally birgalikdagi eng aniq misol.
""")Natijaning muhim qismi:
=== 1. Resurs yopish ===
Usul Xatosiz Xato bilan Yopildimi
──────────────────────────────────────────────────────────────────
Yopishsiz OK ❌ RuntimeError ⚠️ YO'Q
finally OK ❌ RuntimeError ✅
with OK ❌ RuntimeError ✅
=== 2. Bir nechta resurs ===
⭐ YOPISH TARTIBI: TESKARI (LIFO)
Ochildi: A → B → C
Yopildi: C → B → A
=== ⚠️ 4. Yopishda xato ===
Asl xato=False → ❌ OSError: A yopilmadi
Asl xato=True → ❌ OSError: A yopilmadi (kontekst: RuntimeError)
✅ Xavfsiz yopish:
Asl xato=True → ❌ RuntimeError: A da xatoNima ko'rsatdi: 2.3, 2.6, 2.7-bo'limlar.
Misol 3 — with va kontekst menejerlari
"""try/finally ning zamonaviy muqobili."""
from __future__ import annotations
import contextlib
import io
import time
from contextlib import contextmanager, ExitStack, suppress
from pathlib import Path
print("=== ⭐ 1. with = try/finally ===\n")
print(""" Bu ikkisi TENG:
f = open(yol) with open(yol) as f:
try: ishla(f)
ishla(f)
finally:
f.close()
⭐ with — qisqaroq, xavfsizroq, o'qiladigan
""")
class Menejer:
"""Kontekst menejeri protokoli."""
def __init__(self, nom: str, yutsinmi: bool = False):
self.nom = nom
self.yutsinmi = yutsinmi
self.izlar: list[str] = []
def __enter__(self):
self.izlar.append(f"__enter__({self.nom})")
return self # ⭐ `as` ga beriladi
def __exit__(self, tur, qiymat, tb):
"""⭐ Uch argument: istisno turi, obyekti, traceback."""
if tur is None:
self.izlar.append(f"__exit__({self.nom}): xato yo'q")
else:
self.izlar.append(
f"__exit__({self.nom}): {tur.__name__}: {qiymat}"
)
return self.yutsinmi # ⭐ True → istisno YUTILADI
print(f" Xatosiz:")
m = Menejer("A")
with m as r:
m.izlar.append("blok ichida")
for q in m.izlar:
print(f" {q}")
print(f"\n Xato bilan (yutilmaydi):")
m = Menejer("B")
try:
with m:
m.izlar.append("blok ichida")
raise ValueError("xato")
except ValueError as e:
m.izlar.append(f"tashqarida ushlandi: {e}")
for q in m.izlar:
print(f" {q}")
print(f"\n Xato bilan (YUTILADI — __exit__ True):")
m = Menejer("C", yutsinmi=True)
with m:
m.izlar.append("blok ichida")
raise ValueError("xato")
m.izlar.append("⭐ davom etdi — istisno yutildi")
for q in m.izlar:
print(f" {q}")
print(f"""
⭐ __exit__ QAYTARISH QIYMATI:
False / None → istisno UZATILADI (odatiy)
True → istisno YUTILADI ⚠️ ehtiyot bo'ling
⚠️ Faqat contextlib.suppress kabi maxsus holatlarda True qaytaring.
""")
print("=== ⭐ 2. @contextmanager ===\n")
@contextmanager
def olchov(nom: str):
"""⭐ Generator bilan kontekst menejeri."""
boshlanish = time.perf_counter()
print(f" ▶ {nom} boshlandi")
try:
yield boshlanish # ⭐ blok shu yerda
finally: # ⭐ har doim
vaqt = (time.perf_counter() - boshlanish) * 1000
print(f" ◀ {nom} tugadi: {vaqt:.2f}ms")
print(f" Xatosiz:")
with olchov("ish"):
time.sleep(0.005)
print(f"\n Xato bilan:")
try:
with olchov("xatoli ish"):
time.sleep(0.003)
raise ValueError("xato")
except ValueError as e:
print(f" ❌ {e} ⭐ vaqt baribir o'lchandi")
@contextmanager
def vaqtincha(lugat: dict, **ozgarishlar):
"""⭐ Holatni vaqtincha o'zgartirish."""
eski = {k: lugat.get(k) for k in ozgarishlar}
yoq = [k for k in ozgarishlar if k not in lugat]
lugat.update(ozgarishlar)
try:
yield lugat
finally:
lugat.update(eski)
for k in yoq:
lugat.pop(k, None)
SOZLAMA = {"debug": False, "chegara": 100}
print(f"\n Holat qaytarish:")
print(f" Oldin: {SOZLAMA}")
with vaqtincha(SOZLAMA, debug=True, yangi="qiymat"):
print(f" Ichida: {SOZLAMA}")
print(f" Keyin: {SOZLAMA} ✅")
@contextmanager
def yutish_va_jurnal(*turlar):
"""⭐ Xatoni yutib, jurnalga yozish."""
try:
yield
except turlar as e:
print(f" ⚠️ Yutildi: {type(e).__name__}: {e}")
print(f"\n Yutish:")
with yutish_va_jurnal(ValueError, KeyError):
raise KeyError("kalit")
print(f" ⭐ davom etdi")
print("\n\n=== 3. contextlib vositalari ===\n")
print(f" suppress — ataylab yutish:\n")
import os
import tempfile
with tempfile.TemporaryDirectory() as tmp:
yol = Path(tmp) / "yoq.txt"
print(f" try/except bilan:")
try:
os.remove(yol)
except FileNotFoundError:
pass
print(f" 4 qator")
print(f"\n suppress bilan:")
with suppress(FileNotFoundError):
os.remove(yol)
print(f" 2 qator ✅")
print(f"\n Path.unlink(missing_ok=True):")
yol.unlink(missing_ok=True)
print(f" 1 qator ✅✅")
print(f"\n redirect_stdout / redirect_stderr:\n")
bufer = io.StringIO()
with contextlib.redirect_stdout(bufer):
print("Bu buferga tushadi")
print("Bu ham")
print(f" Ushlangan: {bufer.getvalue().strip()!r}")
print(f"\n closing — close() metodi bor obyektlar uchun:\n")
class EskiResurs:
"""__enter__/__exit__ yo'q, faqat close()."""
def __init__(self): self.ochiq = True
def close(self): self.ochiq = False
r = EskiResurs()
with contextlib.closing(r):
print(f" Ichida: ochiq={r.ochiq}")
print(f" Keyin: ochiq={r.ochiq} ✅")
print(f"\n nullcontext — shartli kontekst:\n")
def ishla(fayl=None):
"""⭐ fayl bo'lsa ochamiz, bo'lmasa — hech narsa."""
menejer = (open(fayl, "w", encoding="utf-8") if fayl
else contextlib.nullcontext(io.StringIO()))
with menejer as f:
f.write("natija")
return "faylga" if fayl else "buferga"
print(f" ishla() = {ishla()}")
print(f"\n ExitStack — dinamik:\n")
@contextmanager
def raqamli(n: int):
print(f" + {n}")
try:
yield n
finally:
print(f" - {n}")
with ExitStack() as stack:
qiymatlar = [stack.enter_context(raqamli(i)) for i in range(3)]
print(f" Ichida: {qiymatlar}")
print(f"\n ⭐ Yopish tartibi: teskari (2, 1, 0)")
print(f"\n ExitStack — shartli:\n")
def shartli_ish(jurnal: bool, olcha: bool):
with ExitStack() as stack:
if jurnal:
stack.enter_context(yutish_va_jurnal(ValueError))
if olcha:
stack.enter_context(olchov("shartli"))
return "ishladi"
print(f" Ikkalasi ham:")
print(f" {shartli_ish(True, True)}")
print(f" Hech biri:")
print(f" {shartli_ish(False, False)}")
print("\n\n=== ⭐ 4. try/finally vs with ===\n")
print("""
┌────────────────────────┬──────────────────┬──────────────────┐
│ Mezon │ try/finally │ with │
├────────────────────────┼──────────────────┼──────────────────┤
│ Kod hajmi │ ⚠️ 4-5 qator │ ✅ 2 qator │
│ Ochish xatosi │ ⚠️ ehtiyot │ ✅ avtomatik │
│ Ko'p resurs │ ⚠️ ichma-ich │ ✅ vergul bilan │
│ Dinamik son │ ⚠️ murakkab │ ✅ ExitStack │
│ Qayta ishlatish │ ❌ har joyda │ ✅ menejer sinfi │
│ Istisno yutish │ ✅ except │ ⚠️ __exit__ True │
│ Ixtiyoriy tozalash │ ✅ oson │ ⚠️ nullcontext │
│ Vaqtinchalik holat │ ⚠️ qo'lda │ ✅ @contextmanager│
└────────────────────────┴──────────────────┴──────────────────┘
⭐ QOIDA:
Resurs (fayl, ulanish, qulf) → with
Vaqtinchalik holat → @contextmanager
Bir martalik tozalash → try/finally
Murakkab nazorat oqimi → try/except/else/finally
""")
print("=== 5. Amaliy: fayl quvuri ===\n")
@contextmanager
def atomik_yozish(yol: Path, encoding: str = "utf-8"):
"""⭐ Vaqtinchalik faylga yozib, keyin almashtiradi.
Xato bo'lsa — asl fayl BUZILMAYDI.
"""
yol = Path(yol)
vaqtinchalik = yol.with_suffix(yol.suffix + ".tmp")
f = vaqtinchalik.open("w", encoding=encoding)
try:
yield f
f.close()
vaqtinchalik.replace(yol) # ⭐ atomik
except BaseException:
f.close()
vaqtinchalik.unlink(missing_ok=True) # ⭐ tozalash
raise
finally:
if not f.closed:
f.close()
with tempfile.TemporaryDirectory() as tmp:
yol = Path(tmp) / "malumot.txt"
yol.write_text("ASL MAZMUN", encoding="utf-8")
print(f" Boshlang'ich: {yol.read_text(encoding='utf-8')!r}\n")
print(f" Muvaffaqiyatli yozish:")
with atomik_yozish(yol) as f:
f.write("YANGI MAZMUN")
print(f" Natija: {yol.read_text(encoding='utf-8')!r} ✅")
print(f"\n Xato bilan yozish:")
try:
with atomik_yozish(yol) as f:
f.write("YARIM YOZILDI")
raise RuntimeError("xato")
except RuntimeError as e:
print(f" ❌ {e}")
print(f" Natija: {yol.read_text(encoding='utf-8')!r} "
f"⭐ oldingi mazmun saqlandi ('YARIM YOZILDI' emas)")
qoldiq = list(Path(tmp).glob("*.tmp"))
print(f" Vaqtinchalik fayllar: {qoldiq or '✅ tozalandi'}")
print(f"""
⭐ ATOMIK YOZISH NAQSHI:
1. Vaqtinchalik faylga yoz
2. Muvaffaqiyat → replace() (atomik)
3. Xato → vaqtinchalikni o'chir, asl fayl tegilmaydi
⭐ Bu — sozlama fayllari, ma'lumot bazasi, jurnal uchun
standart yondashuv.
""")
print("=== 6. Ichma-ich kontekstlar ===\n")
@contextmanager
def qatlam(nom: str, xato: bool = False):
print(f" {' ' * qatlam.chuqurlik}▶ {nom}")
qatlam.chuqurlik += 1
try:
yield nom
if xato:
raise ValueError(f"{nom} da xato")
finally:
qatlam.chuqurlik -= 1
print(f" {' ' * qatlam.chuqurlik}◀ {nom}")
qatlam.chuqurlik = 0
print(f" Xatosiz:")
with qatlam("tashqi"):
with qatlam("o'rta"):
with qatlam("ichki"):
print(f" ⭐ ish")
print(f"\n Ichki qatlamda xato:")
try:
with qatlam("tashqi"):
with qatlam("o'rta"):
with qatlam("ichki"):
raise RuntimeError("ichki xato")
except RuntimeError as e:
print(f" ❌ {e}")
print(f"""
⭐ TESKARI TARTIBDA yopiladi — har qatlam o'z tozalashini
bajaradi, xato bo'lsa ham.
⚠️ Bu — try/finally bilan qilinsa 12+ qator bo'lardi.
""")Natijaning muhim qismi:
=== ⭐ 1. with = try/finally ===
Xato bilan (YUTILADI — __exit__ True):
__enter__(C)
blok ichida
__exit__(C): ValueError: xato
⭐ davom etdi — istisno yutildi
=== ⭐ 2. @contextmanager ===
Xato bilan:
▶ xatoli ish boshlandi
◀ xatoli ish tugadi: 3.15ms
❌ xato ⭐ vaqt baribir o'lchandi
=== 5. Amaliy: fayl quvuri ===
Xato bilan yozish:
❌ xato
Natija: 'YANGI MAZMUN' ⭐ oldingi mazmun saqlandi ('YARIM YOZILDI' emas)
Vaqtinchalik fayllar: ✅ tozalandiNima ko'rsatdi: 2.6-bo'lim.
Misol 4 — Amaliy: ishonchli quvur
"""try/except/else/finally to'liq loyihada."""
from __future__ import annotations
import contextlib
import io
import json
import logging
import time
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from pathlib import Path
from typing import Any, Callable, Iterator
print("=== MA'LUMOT QUVURI ===\n")
jurnal = logging.getLogger("quvur")
jurnal.setLevel(logging.DEBUG)
_bufer = io.StringIO()
_h = logging.StreamHandler(_bufer)
_h.setFormatter(logging.Formatter("%(levelname)-8s %(message)s"))
jurnal.addHandler(_h)
jurnal.propagate = False
class Holat(str, Enum):
KUTILMOQDA = "kutilmoqda"
BAJARILMOQDA = "bajarilmoqda"
MUVAFFAQIYAT = "muvaffaqiyat"
XATO = "xato"
BEKOR = "bekor"
def __str__(self): return self.value
@dataclass
class BosqichNatijasi:
nom: str
holat: Holat = Holat.KUTILMOQDA
vaqt_ms: float = 0.0
xato: Exception | None = None
chiqish: Any = None
def __str__(self):
belgi = {"muvaffaqiyat": "✅", "xato": "❌",
"bekor": "⊘", "kutilmoqda": "○",
"bajarilmoqda": "◐"}[str(self.holat)]
x = f" — {type(self.xato).__name__}: {self.xato}" if self.xato else ""
return f"{belgi} {self.nom:<20} {self.vaqt_ms:>7.2f}ms{x}"
class Resurs:
"""Kuzatiladigan resurs."""
OCHIQ: list[str] = []
def __init__(self, nom: str):
self.nom = nom
self.yopilgan = False
Resurs.OCHIQ.append(nom)
jurnal.debug("Resurs ochildi: %s", nom)
def yop(self):
if not self.yopilgan:
self.yopilgan = True
with contextlib.suppress(ValueError):
Resurs.OCHIQ.remove(self.nom)
jurnal.debug("Resurs yopildi: %s", self.nom)
def __enter__(self): return self
def __exit__(self, *_): self.yop(); return False
class Quvur:
"""⭐ try/except/else/finally to'liq ishlatilgan.
HAR BOSQICHDA:
try — bosqichni bajarish
except — xatoni yozish, orqaga qaytarish
else — natijani keyingi bosqichga
finally — vaqt o'lchash, resurs yopish
"""
def __init__(self, *, toxtat_xatoda: bool = True,
orqaga_qaytar: bool = True):
self.bosqichlar: list[tuple[str, Callable, Callable | None]] = []
self.toxtat_xatoda = toxtat_xatoda
self.orqaga_qaytar = orqaga_qaytar
self.natijalar: list[BosqichNatijasi] = []
self._bajarilgan: list[tuple[str, Callable, Any]] = []
def bosqich(self, nom: str, f: Callable,
bekor: Callable | None = None) -> "Quvur":
"""⭐ bekor — orqaga qaytarish funksiyasi."""
self.bosqichlar.append((nom, f, bekor))
return self
def _bosqich_bajar(self, nom: str, f: Callable,
bekor: Callable | None,
kirish: Any) -> BosqichNatijasi:
"""⭐ Bitta bosqich — to'liq himoya."""
n = BosqichNatijasi(nom=nom, holat=Holat.BAJARILMOQDA)
boshlanish = time.perf_counter()
try:
chiqish = f(kirish)
except Exception as e:
n.holat = Holat.XATO
n.xato = e
jurnal.warning("Bosqich '%s' xato: %s", nom, e)
else: # ⭐ xato bo'lmaganda
n.holat = Holat.MUVAFFAQIYAT
n.chiqish = chiqish
if bekor is not None:
self._bajarilgan.append((nom, bekor, chiqish))
jurnal.debug("Bosqich '%s' bajarildi", nom)
finally: # ⭐ har doim
n.vaqt_ms = (time.perf_counter() - boshlanish) * 1000
return n
def _orqaga(self) -> list[str]:
"""⭐ Teskari tartibda orqaga qaytarish."""
qaytarilgan = []
for nom, bekor, chiqish in reversed(self._bajarilgan):
try:
bekor(chiqish)
qaytarilgan.append(nom)
jurnal.info("Orqaga qaytarildi: %s", nom)
except Exception as e: # ⭐ bittasi buzilsa
jurnal.error("Orqaga qaytarishda xato (%s): %s", nom, e)
self._bajarilgan.clear()
return qaytarilgan
def bajar(self, kirish: Any = None) -> tuple[Any, list[BosqichNatijasi]]:
"""⭐ Butun quvur."""
self.natijalar.clear()
self._bajarilgan.clear()
joriy = kirish
xato_bor = False
boshlanish = time.perf_counter()
try:
for nom, f, bekor in self.bosqichlar:
if xato_bor and self.toxtat_xatoda:
self.natijalar.append(
BosqichNatijasi(nom=nom, holat=Holat.BEKOR)
)
continue
n = self._bosqich_bajar(nom, f, bekor, joriy)
self.natijalar.append(n)
if n.holat is Holat.XATO:
xato_bor = True
if self.toxtat_xatoda:
continue
else:
joriy = n.chiqish
if xato_bor and self.orqaga_qaytar:
qaytarilgan = self._orqaga()
if qaytarilgan:
jurnal.info("Orqaga qaytarildi: %s",
", ".join(qaytarilgan))
except BaseException: # ⭐ Ctrl+C ham
jurnal.exception("Quvurda kutilmagan xato")
if self.orqaga_qaytar:
self._orqaga()
raise
else: # ⭐ xato bo'lmaganda
if not xato_bor:
jurnal.info("Quvur muvaffaqiyatli")
finally: # ⭐ har doim
jami = (time.perf_counter() - boshlanish) * 1000
jurnal.info("Quvur tugadi: %.2fms", jami)
self._bajarilgan.clear()
return (None if xato_bor else joriy), self.natijalar
def hisobot(self) -> str:
q = ["", "─" * 56]
for n in self.natijalar:
q.append(f" {n}")
q.append("─" * 56)
muvaffaqiyat = sum(1 for n in self.natijalar
if n.holat is Holat.MUVAFFAQIYAT)
xato = sum(1 for n in self.natijalar if n.holat is Holat.XATO)
bekor = sum(1 for n in self.natijalar if n.holat is Holat.BEKOR)
jami_vaqt = sum(n.vaqt_ms for n in self.natijalar)
q.append(f" ✅ {muvaffaqiyat} ❌ {xato} ⊘ {bekor} "
f"jami {jami_vaqt:.2f}ms")
return "\n".join(q)
# ═══ BOSQICHLAR ═══
HOLAT: dict[str, Any] = {"fayllar": [], "baza": [], "kesh": {}}
def yukla(_):
jurnal.debug("Ma'lumot yuklanmoqda")
time.sleep(0.002)
return [
{"id": 1, "ism": "Aziz", "maosh": 8_500_000},
{"id": 2, "ism": "Malika", "maosh": 7_000_000},
{"id": 3, "ism": "Bobur", "maosh": 9_500_000},
]
def tekshir(m):
time.sleep(0.001)
for q in m:
if not isinstance(q.get("maosh"), int):
raise ValueError(f"Noto'g'ri maosh: {q}")
return m
def fayl_yoz(m):
time.sleep(0.001)
nom = f"hisobot_{len(HOLAT['fayllar']) + 1}.json"
HOLAT["fayllar"].append(nom)
return nom
def fayl_ochir(nom):
HOLAT["fayllar"].remove(nom)
def bazaga_yoz(nom):
time.sleep(0.002)
yozuv = f"db:{nom}"
HOLAT["baza"].append(yozuv)
return yozuv
def bazadan_ochir(yozuv):
HOLAT["baza"].remove(yozuv)
def keshla(yozuv):
HOLAT["kesh"][yozuv] = datetime.now()
return yozuv
def keshdan_ochir(yozuv):
HOLAT["kesh"].pop(yozuv, None)
def xabar_yubor(yozuv):
time.sleep(0.001)
return f"✉ {yozuv}"
def xato_bosqich(m):
raise RuntimeError("Tashqi xizmat ishlamayapti")
print("1. Muvaffaqiyatli quvur:\n")
q = (Quvur()
.bosqich("Yuklash", yukla)
.bosqich("Tekshirish", tekshir)
.bosqich("Faylga yozish", fayl_yoz, fayl_ochir)
.bosqich("Bazaga yozish", bazaga_yoz, bazadan_ochir)
.bosqich("Keshlash", keshla, keshdan_ochir)
.bosqich("Xabar", xabar_yubor))
natija, _ = q.bajar()
print(q.hisobot())
print(f"\n Natija: {natija}")
print(f" Holat: fayllar={HOLAT['fayllar']}, baza={HOLAT['baza']}, "
f"kesh={len(HOLAT['kesh'])}")
print("\n\n2. ⭐ Xato + orqaga qaytarish:\n")
HOLAT["fayllar"].clear(); HOLAT["baza"].clear(); HOLAT["kesh"].clear()
q2 = (Quvur()
.bosqich("Yuklash", yukla)
.bosqich("Tekshirish", tekshir)
.bosqich("Faylga yozish", fayl_yoz, fayl_ochir)
.bosqich("Bazaga yozish", bazaga_yoz, bazadan_ochir)
.bosqich("Tashqi xizmat", xato_bosqich) # ⚠️ xato
.bosqich("Keshlash", keshla, keshdan_ochir)
.bosqich("Xabar", xabar_yubor))
natija, _ = q2.bajar()
print(q2.hisobot())
print(f"\n Natija: {natija}")
print(f" Holat: fayllar={HOLAT['fayllar']}, baza={HOLAT['baza']}, "
f"kesh={len(HOLAT['kesh'])}")
print(f" ⭐ HAMMASI ORQAGA QAYTARILDI")
print("\n\n3. Xatoda to'xtamaslik:\n")
HOLAT["fayllar"].clear(); HOLAT["baza"].clear(); HOLAT["kesh"].clear()
q3 = (Quvur(toxtat_xatoda=False, orqaga_qaytar=False)
.bosqich("Yuklash", yukla)
.bosqich("Xato-1", xato_bosqich)
.bosqich("Tekshirish", tekshir)
.bosqich("Xato-2", xato_bosqich)
.bosqich("Faylga yozish", fayl_yoz, fayl_ochir))
natija, _ = q3.bajar()
print(q3.hisobot())
print(f"\n ⭐ Xatoga qaramay bosqichlar davom etdi")
print(f" Holat: fayllar={HOLAT['fayllar']}")
print("\n\n4. ⭐ Resurs boshqaruvi:\n")
Resurs.OCHIQ.clear()
def resursli_ish(xato: bool):
"""⭐ Ichma-ich resurslar + finally."""
with contextlib.ExitStack() as stack:
r1 = stack.enter_context(Resurs("baza"))
r2 = stack.enter_context(Resurs("fayl"))
r3 = stack.enter_context(Resurs("tarmoq"))
print(f" Ochiq: {Resurs.OCHIQ}")
if xato:
raise RuntimeError("ish paytida xato")
return "OK"
for xato in [False, True]:
Resurs.OCHIQ.clear()
print(f" Xato={xato}:")
try:
n = resursli_ish(xato)
print(f" Natija: {n}")
except RuntimeError as e:
print(f" ❌ {e}")
print(f" Yopilgandan keyin: "
f"{Resurs.OCHIQ or '✅ hammasi yopildi'}\n")
print("5. Vaqt statistikasi:\n")
HOLAT["fayllar"].clear(); HOLAT["baza"].clear(); HOLAT["kesh"].clear()
natija, natijalar = q.bajar()
jami = sum(n.vaqt_ms for n in natijalar)
print(f" {'Bosqich':<20} {'Vaqt':>10} {'Ulush':>8} {'Diagramma'}")
print(" " + "─" * 60)
for n in sorted(natijalar, key=lambda x: -x.vaqt_ms):
ulush = n.vaqt_ms / jami * 100 if jami else 0
diagramma = "█" * int(ulush / 4)
print(f" {n.nom:<20} {n.vaqt_ms:>8.2f}ms {ulush:>7.1f}% {diagramma}")
print(f" {'JAMI':<20} {jami:>8.2f}ms")
print("\n\n6. Jurnal:\n")
for q_ in _bufer.getvalue().rstrip().split("\n")[:12]:
print(f" {q_}")
qolgan = len(_bufer.getvalue().rstrip().split("\n")) - 12
if qolgan > 0:
print(f" ... yana {qolgan} qator")
print(f"""
⭐ BU LOYIHADA:
HAR BOSQICHDA:
try → bosqichni bajarish
except → xatoni yozish, jurnal
else → ⭐ natijani saqlash, orqaga qaytarish ro'yxatiga
finally → ⭐ vaqt o'lchash (xato bo'lsa ham)
QUVUR DARAJASIDA:
try → barcha bosqichlar
except → ⭐ BaseException (Ctrl+C ham) + orqaga qaytarish
else → muvaffaqiyat jurnali
finally → ⭐ jami vaqt, tozalash
ORQAGA QAYTARISH:
Teskari tartibda (LIFO)
Har biri o'z try da — bittasi buzilsa qolganlar davom etadi
RESURSLAR:
ExitStack — dinamik son
Xato bo'lsa ham hammasi yopiladi
⭐ else NEGA MUHIM:
`else` da natija saqlanadi va orqaga qaytarish ro'yxatiga
qo'shiladi — FAQAT bosqich muvaffaqiyatli bo'lganda.
Agar bu `try` ichida bo'lsa — xato bo'lgan bosqich ham
ro'yxatga tushib qolardi.
""")Natijaning muhim qismi:
2. ⭐ Xato + orqaga qaytarish:
────────────────────────────────────────────────────────
✅ Yuklash 2.31ms
✅ Tekshirish 1.12ms
✅ Faylga yozish 1.09ms
✅ Bazaga yozish 2.15ms
❌ Tashqi xizmat 0.02ms — RuntimeError: Tashqi xizmat...
⊘ Keshlash 0.00ms
⊘ Xabar 0.00ms
────────────────────────────────────────────────────────
✅ 4 ❌ 1 ⊘ 2 jami 6.69ms
Holat: fayllar=[], baza=[], kesh=0
⭐ HAMMASI ORQAGA QAYTARILDI
4. ⭐ Resurs boshqaruvi:
Xato=True:
Ochiq: ['baza', 'fayl', 'tarmoq']
❌ ish paytida xato
Yopilgandan keyin: ✅ hammasi yopildiNima ko'rsatdi: 2.1, 2.2, 2.3, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"else — except bilan bir xil" |
Xato bo'lmaganda bajariladi |
"else ortiqcha" |
try ni qisqartiradi, xato yashirilmaydi |
"finally return da bajarilmaydi" |
Har doim bajariladi |
"finally da return xavfsiz" |
Asl qiymat/istisno yo'qoladi |
"finally — resurs uchun yagona yo'l" |
with yaxshiroq |
"try/finally va with bir xil" |
with ochish xatosini ham hal qiladi |
"__exit__ True qaytarishi normal" |
Istisno yutiladi |
"else except siz ishlaydi" |
SyntaxError |
6. Keng tarqalgan xatolar va yechimlari
1. finally da return
try: return 1
finally: return 2 # ⚠️ 2 qaytadi
finally: jurnal.info(...) # ✅2. Juda keng try
try:
m = json.loads(s)
ishla(m) # ⚠️ else ga
except ValueError: ...
else:
ishla(m) # ✅3. finally da xato
finally:
r.yop() # ⚠️ asl xatoni almashtiradi
finally:
try: r.yop()
except Exception: jurnal.exception(...) # ✅4. Ochishdan keyin try boshlamaslik
a = ochish(); b = ochish() # ⚠️ b xato bersa a yopilmaydi
try: ...
finally: a.yop(); b.yop()
with ochish() as a, ochish() as b: # ✅5. else o'rniga try oxiri
try:
q = ol()
return ishla(q) # ⚠️ ishla xatosi ham ushlanadi
except KeyError: return None
else:
return ishla(q) # ✅6. finally da break/continue
for i in ...:
try: break
finally: continue # ⚠️ cheksiz tsikl7. with o'rniga try/finally
f = open(y)
try: ...
finally: f.close() # ⚠️ 4 qator
with open(y) as f: ... # ✅ 1 qator8. __exit__ da True
def __exit__(self, *a): return True # ⚠️ barcha istisno yutiladi
def __exit__(self, *a): return False # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 9.2-dars (o'tilgan):
try/except - 9.5-dars:
raiseva qayta ko'tarish - 10-qism: kontekst menejerlari — to'liq
contextlib:contextmanager,ExitStack,suppress,closingthreading.Lock,sqlite3,open()— barchasi kontekst menejeri- PEP 343: The "with" Statement
8. Eng yaxshi amaliyotlar
tryblokini eng qisqa tuting. Faqat xato berishi mumkin bo'lgan qator.Muvaffaqiyat kodi
elseda. Xato yashirilmaydi.finallyfaqat tozalash uchun.return/break/continueyozmang.Resurs uchun
with.try/finally— faqat maxsus holatlarda.finallydagi xatoni yuting. Asl xato saqlansin.Ochishdan keyin darhol
try. Yokiwith ... as a, ... as b.Dinamik resurslar uchun
ExitStack.Tranzaksiya naqshi:
except→ bekor,else→ tasdiqla,finally→ yop.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
1. def f():
try: return 1
finally: return 2
print(f())
2. def f():
try: raise ValueError()
finally: return 1
print(f())
3. def f():
try:
x = 1
return x
finally: x = 2
print(f())
4. def f():
try:
lst = [1]
return lst
finally: lst.append(2)
print(f())
5. def f():
try: return 1
except: return 2
else: return 3
finally: print("f")
print(f())
6. try: pass
else: print("e")
7. for i in range(3):
try: continue
finally: print(i, end=" ")
8. def f():
try: 1/0
except ZeroDivisionError: return "e"
finally: print("f", end=" ")
print(f())
9. try:
try: raise ValueError("a")
finally: raise TypeError("b")
except Exception as e:
print(type(e).__name__, type(e.__context__).__name__)
10. def f():
for i in range(3):
try: return i
finally: print("f", end=" ")
print(f())
11. import contextlib
with contextlib.suppress(ValueError):
raise ValueError("x")
print("davom")
12. class M:
def __enter__(self): return self
def __exit__(self, *a): return True
with M(): raise ValueError()
print("davom")Javoblar
21— istisno yutildi1— qiymat saqlangan[1, 2]— havolafkeyin1—elsebajarilmaydiSyntaxError—elseexceptsiz0 1 2f eTypeError ValueErrorf 0davomdavom—__exit__True
Vazifa 2: Xatolarni tuzating
1. try: return 1
finally: return 2
2. try:
m = json.loads(s)
ishla(m)
except ValueError: jurnal.error("JSON")
3. f = open(y)
ishla(f)
f.close()
4. a = ochish(); b = ochish()
try: ...
finally: a.yop(); b.yop()
5. finally: r.yop() # yop() xato berishi mumkin
6. for i in ...:
try: break
finally: continue
7. qulf.acquire()
ish()
qulf.release()
8. def __exit__(self, *a): return TrueJavoblar
1. finally da return olib tashlang
2. ishla(m) ni else blokiga
3. with open(y) as f: ishla(f)
4. with ochish() as a, ochish() as b:
5. finally: try: r.yop() except: jurnal.exception(...)
6. finally da continue olib tashlang
7. with qulf: ish()
8. return False (yoki hech narsa)Vazifa 3: Tranzaksiya menejeri
Yozing:
@contextmanagerbilan tranzaksiya- Muvaffaqiyat →
commit, xato →rollback finallyda ulanishni yopish- Ichma-ich tranzaksiyalar (savepoint)
- Faqat ma'lum xatolarda rollback
- Statistika: commit/rollback soni
Vazifa 4: finally tekshiruvchisi
Vosita yozing (AST bilan):
finallydareturnlarni topsinfinallydabreak/continuefinallyda xato berishi mumkin bo'lgan chaqiruvlartrybloki 5 qatordan uzun bo'lsaelseishlatilmagan joylarni (tavsiya)try/finallyo'rnigawithmumkin bo'lgan joylarni
Vazifa 5: Resurs hovuzi
ExitStackbilan dinamik resurslar- Ochishda xato → oldingilarini yopish
- Yopishda xato → jurnalga, qolganlarini yopish
- Timeout bilan ochish
- Statistika: ochilgan/yopilgan/oqib ketgan
- Kontekst menejeri sifatida
Vazifa 6: Qayta urinish + tozalash
- Har urinishda resurs ochiladi/yopiladi
finallyda har urinish vaqti o'lchanadi- Muvaffaqiyat →
elseda natija - Barcha urinishlar xato → yakuniy istisno
- Orqaga qaytarish (agar qisman bajarilgan bo'lsa)
- To'liq jurnal
Vazifa 7: O'ylash
Nega Python try/finally bo'la turib with ni qo'shdi?
Javob
Chunki try/finally to'g'ri ishlatish qiyin, va tozalash mantiqi har joyda takrorlanardi.
1. Muammo: takrorlanish
# Har fayl ochishda:
f = open(yol)
try:
ishla(f)
finally:
f.close()
# Har qulfda:
qulf.acquire()
try:
ish()
finally:
qulf.release()
# Har ulanishda:
ulanish = ulan()
try:
sorov()
finally:
ulanish.yop()Naqsh bir xil, lekin har joyda qayta yoziladi.
2. Muammo: to'g'ri ishlatish qiyin
a) Ochishdan keyin try:
# ❌ NOTO'G'RI
try:
f = open(yol) # ⚠️ ochishda xato bo'lsa
ishla(f)
finally:
f.close() # ❌ NameError — f yo'q
# ✅ TO'G'RI
f = open(yol)
try:
ishla(f)
finally:
f.close()Bu xato juda ko'p uchraydi.
b) Bir necha resurs:
# ❌ NOTO'G'RI
a = ochish("a")
b = ochish("b") # ⚠️ b xato bersa a yopilmaydi
try:
ish(a, b)
finally:
a.yop()
b.yop()
# ✅ TO'G'RI — ichma-ich
a = ochish("a")
try:
b = ochish("b")
try:
ish(a, b)
finally:
b.yop()
finally:
a.yop()3 resurs = 3 daraja, 12 qator.
c) Yopishda xato:
finally:
f.close() # ⚠️ bu ham xato berishi mumkin
# → asl xato yashirinadi3. PEP 343 (2005) motivatsiyasi
Guido va Nick Coghlan yozdi:
"This PEP adds a new statement
withto the Python language to make it possible to factor out standard uses oftry/finallystatements."
Uch maqsad:
- Takrorlanishni yo'q qilish — tozalash mantiqi bir joyda
- Xatolarni oldini olish —
f = open()trydan tashqarida - O'qilishni yaxshilash — niyat ko'rinadi
4. with nima beradi
with open(yol) as f:
ishla(f)Aslida:
menejer = open(yol)
chiqish = type(menejer).__exit__
kirish = type(menejer).__enter__
qiymat = kirish(menejer)
xato = True
try:
try:
f = qiymat
ishla(f)
except BaseException:
xato = False
if not chiqish(menejer, *sys.exc_info()):
raise
finally:
if xato:
chiqish(menejer, None, None, None)12 qator → 2 qator.
5. Qo'shimcha imkoniyatlar
with faqat qisqartma emas — u yangi imkoniyatlar beradi:
a) Ochish xatosi avtomatik hal qilinadi:
with ochish("a") as a, ochish("b") as b: # ⭐ b xato bersa a yopiladi
...b) __exit__ istisnoni ko'radi:
def __exit__(self, tur, qiymat, tb):
if tur is not None:
self.rollback() # ⭐ xato bo'lsa
else:
self.commit() # ⭐ bo'lmasa
return False try/finally da bu mumkin emas — finally istisno haqida bilmaydi.
c) Istisnoni yutish:
with contextlib.suppress(FileNotFoundError):
os.remove(yol) # ⭐ 2 qatord) Qayta ishlatiladigan mantiq:
@contextmanager
def tranzaksiya(db):
db.begin()
try:
yield db
except Exception:
db.rollback()
raise
else:
db.commit()
finally:
db.close()
# ⭐ Endi har joyda:
with tranzaksiya(db):
...e) Dinamik son:
with ExitStack() as stack:
fayllar = [stack.enter_context(open(y)) for y in yollar] try/finally bilan bu juda murakkab.
6. Standart kutubxonada
with qo'shilgach, deyarli hamma narsa kontekst menejeri bo'ldi:
open() fayl
threading.Lock() qulf
sqlite3.connect() tranzaksiya
socket.socket() soket
subprocess.Popen() jarayon
tempfile.TemporaryFile() vaqtinchalik fayl
decimal.localcontext() aniqlik konteksti
unittest.mock.patch() vaqtinchalik almashtirish
pytest.raises() istisno kutish
zipfile.ZipFile() arxiv
multiprocessing.Pool() jarayonlar hovuzi
asyncio.Lock() async qulf Bu — with ning eng katta muvaffaqiyati: u standart bo'lib qoldi.
7. Boshqa tillar
| Til | Mexanizm |
|---|---|
| Python | with + __enter__/__exit__ |
| C# | using + IDisposable |
| Java | try-with-resources (7+) + AutoCloseable |
| Go | defer |
| Rust | Drop trait — avtomatik |
| C++ | RAII — avtomatik |
| JavaScript | try/finally (using — taklif) |
Rust va C++ eng yaxshi:
{
let f = File::open(yol)?; // ⭐ hech qanday `with` kerak emas
ishla(&f);
} // ⭐ f bu yerda AVTOMATIK yopiladiEgalik tizimi tufayli obyekt qamrovdan chiqqanda avtomatik tozalanadi. Dasturchi hech narsa yozmaydi.
Go — defer:
f, err := os.Open(yol)
if err != nil { return err }
defer f.Close() // ⭐ funksiya oxirida
ishla(f) defer — funksiya oxirida, blok emas. Tsiklda muammo:
for _, y := range yollar {
f, _ := os.Open(y)
defer f.Close() // ⚠️ HAMMASI funksiya oxirida!
}Java:
try (var f = new FileReader(yol)) {
ishla(f);
} // ⭐ avtomatik yopiladi Python with ga juda o'xshash (2011 da qo'shilgan, Python dan 6 yil keyin).
8. try/finally hali ham kerakmi
Ha, ba'zi holatlarda:
# 1. Kontekst menejeri bo'lmagan tozalash
eski = sozlama.qiymat
sozlama.qiymat = yangi
try:
ish()
finally:
sozlama.qiymat = eski # ⚠️ yoki @contextmanager
# 2. Murakkab nazorat oqimi
try:
ish()
except A:
...
except B:
...
else:
...
finally:
...
# 3. Bir martalik tozalash
try:
ish()
finally:
jurnal.info("tugadi") # ✅ menejer ortiqcha Lekin ko'p holatda @contextmanager yaxshiroq:
@contextmanager
def vaqtincha(obj, atr, qiymat):
eski = getattr(obj, atr)
setattr(obj, atr, qiymat)
try:
yield
finally:
setattr(obj, atr, eski)9. Amaliy qoida
Resurs (fayl, ulanish, qulf) → with
Bir necha resurs → with a, b yoki ExitStack
Vaqtinchalik holat → @contextmanager
Takrorlanadigan tozalash → @contextmanager
Bir martalik tozalash → try/finally
Murakkab nazorat oqimi → try/except/else/finally10. Xulosa
with qo'shildi, chunki try/finally:
- Takrorlanardi — har resursda bir xil naqsh
- To'g'ri yozish qiyin —
f = open()joyi, ichma-ich bloklar - Istisno haqida bilmaydi —
finallyxato bo'lganini ko'rmaydi - Dinamik resurslar bilan murakkab
Va with shunchaki qisqartma emas — u:
- Ochish xatosini avtomatik hal qiladi
__exit__ga istisno ma'lumotini beradi- Qayta ishlatiladigan mantiq yaratadi (
@contextmanager) - Standart protokol bo'lib qoldi (butun stdlib)
Umumiy naqsh (yana): Python takrorlanadigan naqshni ko'rib, uni tilga kiritdi — xuddi for (iteratsiya), @dekorator (o'rash), dataclass (ma'lumot sinfi) kabi.
Nimani mustahkamlaydi: 2.3, 2.6-bo'limlar.
Xulosa
Bu darsda else va finally bloklarini o'rgandik.
Eng muhim uch fikr:
else—tryblokini qisqartiradi va xatoni yashirmaydi.tryichiga faqat xato berishi mumkin bo'lgan qatorni qo'ying; muvaffaqiyat kodielsega. Aks holdaelsedagi tasodifiyValueErrorexcept ValueErrorga tushib, noto'g'ri xabar beriladi.finally— har doim bajariladi, hattoreturnva ushlanmagan istisnoda ham. Lekinfinallydareturn,breakyokicontinueyozmang: ular saqlangan qiymatni yoki ko'tarilayotgan istisnoni jimgina yo'q qiladi.finallyfaqat tozalash uchun — va uning ichidagi xatoni ham yutib, jurnalga yozing, aks holda asl sabab yashirinadi.Resurslar uchun
with—try/finallydan yaxshiroq. U ochish xatosini avtomatik hal qiladi, bir nechta resursni bir qatorda boshqaradi (ExitStackbilan dinamik sonini ham),__exit__ga istisno ma'lumotini beradi va tozalash mantiqini qayta ishlatiladigan qiladi (@contextmanager). Tranzaksiya naqshi esa to'rt blokning barchasini ishlatadi:except→ bekor,else→ tasdiqla,finally→ yop.
Keyingi darsda bir nechta istisnoni birga qayta ishlashni ko'ramiz: except tuple'lari, ExceptionGroup, except* va xato ierarxiyasidan foydalanish.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!