IlmHamroh
Python kursi/Xatolar3/8-dars38 daqiqa
Mundarija (21)

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:

python
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:

python
try:
    m = json.loads(matn)            # ⭐ FAQAT xavfli qism
except json.JSONDecodeError:
    jurnal.error("JSON buzilgan")
else:
    ishla(m)                        # ⭐ xato bo'lmaganda

Va bu — chalkash:

python
def f():
    try:
        return 1
    finally:
        return 2

f()                                 # ⚠️ 2 — birinchi return YO'QOLDI

Bu darsda:

  • else — qachon va nega
  • finally — har doim bajariladi
  • finally va return/break/continue to'qnashuvi
  • To'liq bajarilish tartibi (8 holat)
  • finally va istisno "yutilishi"
  • with — try/finally ning yaxshi muqobili

2. Nazariya — chuqur tushuntirish

2.1. To'liq sintaksis

python
try:
    ...                             # xavfli kod
except Xato1:
    ...                             # xato bo'lsa
except Xato2:
    ...
else:
    ...                             # ⭐ xato BO'LMASA
finally:
    ...                             # ⭐ HAR DOIM

Bajarilish 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:

python
try:
    ...
else:                               # ❌ SyntaxError
    ...

else — faqat except bilan birga.

python
try:
    ...
finally:
    ...                             # ✅ except siz mumkin

2.2. else — nega kerak

Muammo: try bloki juda keng

python
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:

python
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:

  1. Aniqlik — qaysi qator himoyalangani ko'rinadi
  2. Xato yashirilmaydi — else dagi xato except ga tushmaydi
  3. Niyat — "bu faqat muvaffaqiyatda bajariladi"

else va return:

python
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

python
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)
  • return bo'lsa (keyin qaytadi)
  • break/continue bo'lsa
  • sys.exit() bo'lsa (SystemExit — istisno)

Bajarilmaydi:

  • os._exit() — jarayonni darhol o'ldiradi
  • Segfault, elektr o'chishi
  • Cheksiz tsikl try ichida
  • KeyboardInterrupt juda noto'g'ri vaqtda (kamdan-kam)

2.4. finally va return to'qnashuvi

python
def f():
    try:
        return 1                    # ⚠️ qiymat HISOBLANADI
    finally:
        return 2                    # ⚠️ lekin BU qaytadi

f()                                 # 2

Mexanizm:

  1. try da return 1 — qiymat (1) saqlanadi
  2. finally bajariladi
  3. finally da return 2 — yangi qiymat
  4. Birinchisi yo'qoladi

Istisno ham yutiladi:

python
def f():
    try:
        raise ValueError("xato")
    finally:
        return "OK"                 # ⚠️ istisno YO'QOLDI

f()                                 # 'OK' — xato yo'q!

break/continue ham:

python
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

python
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:

python
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:

python
r = ochish()
try:
    ishla(r)
finally:
    r.yop()

B) with — yaxshiroq:

python
with ochish() as r:
    ishla(r)                        # ✅ avtomatik yopiladi

C) Bir nechta resurs:

python
# ⚠️ 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:

python
from contextlib import ExitStack

with ExitStack() as stack:
    fayllar = [stack.enter_context(open(y)) for y in yollar]
    ishla(fayllar)                  # ✅ hammasi yopiladi

2.7. Amaliy naqshlar

Vaqt o'lchash:

python
boshlanish = time.perf_counter()
try:
    ish()
finally:
    vaqt = time.perf_counter() - boshlanish     # ⭐ xato bo'lsa ham
    jurnal.info("Vaqt: %.3fs", vaqt)

Holat qaytarish:

python
eski = sozlama.qiymat
sozlama.qiymat = yangi
try:
    ish()
finally:
    sozlama.qiymat = eski           # ⭐ har doim qaytariladi

Qulf:

python
qulf.acquire()
try:
    kritik_bolim()
finally:
    qulf.release()                  # ⭐ deadlock bo'lmaydi
# yoki: with qulf:

Tranzaksiya:

python
tranzaksiya.boshla()
try:
    amallar()
except Exception:
    tranzaksiya.bekor()
    raise
else:
    tranzaksiya.tasdiqla()
finally:
    ulanish.yop()

3. Tez ma'lumotnoma

To'liq sintaksis

python
try:
    ...             xavfli kod
except X:
    ...             xato bo'lsa
else:
    ...             ⭐ xato BO'LMASA (except bilan birga)
finally:
    ...             ⭐ HAR DOIM

Bajarilish jadvali

              try   except  else  finally
Xato yo'q     ✅    ❌      ✅    ✅
Ushlandi      ⚠️    ✅      ❌    ✅
Ushlanmadi    ⚠️    ❌      ❌    ✅ → ko'tariladi
return        ⚠️    —       ❌    ✅ → qaytadi
break         ⚠️    —       ❌    ✅ → chiqadi

finally tuzoqlari

python
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 YOZMANG

Muqobillar

python
try/finally             asosiy
with                    ✅ yaxshiroq
ExitStack               dinamik ko'p resurs
contextlib.suppress     ataylab yutish

4. Batafsil misollar

Misol 1 — Bajarilish tartibi

python
"""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:

text
=== ⭐ 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

python
"""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:

text
=== 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 xato

Nima ko'rsatdi: 2.3, 2.6, 2.7-bo'limlar.

Misol 3 — with va kontekst menejerlari

python
"""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:

text
=== ⭐ 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: ✅ tozalandi

Nima ko'rsatdi: 2.6-bo'lim.

Misol 4 — Amaliy: ishonchli quvur

python
"""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:

text
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 yopildi

Nima 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

python
try: return 1
finally: return 2                   # ⚠️ 2 qaytadi
finally: jurnal.info(...)           # ✅

2. Juda keng try

python
try:
    m = json.loads(s)
    ishla(m)                        # ⚠️ else ga
except ValueError: ...
else:
    ishla(m)                        # ✅

3. finally da xato

python
finally:
    r.yop()                         # ⚠️ asl xatoni almashtiradi
finally:
    try: r.yop()
    except Exception: jurnal.exception(...)     # ✅

4. Ochishdan keyin try boshlamaslik

python
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

python
try:
    q = ol()
    return ishla(q)                 # ⚠️ ishla xatosi ham ushlanadi
except KeyError: return None
else:
    return ishla(q)                 # ✅

6. finally da break/continue

python
for i in ...:
    try: break
    finally: continue               # ⚠️ cheksiz tsikl

7. with o'rniga try/finally

python
f = open(y)
try: ...
finally: f.close()                  # ⚠️ 4 qator
with open(y) as f: ...              # ✅ 1 qator

8. __exit__ da True

python
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: raise va qayta ko'tarish
  • 10-qism: kontekst menejerlari — to'liq
  • contextlib: contextmanager, ExitStack, suppress, closing
  • threading.Lock, sqlite3, open() — barchasi kontekst menejeri
  • PEP 343: The "with" Statement

8. Eng yaxshi amaliyotlar

  1. try blokini eng qisqa tuting. Faqat xato berishi mumkin bo'lgan qator.

  2. Muvaffaqiyat kodi else da. Xato yashirilmaydi.

  3. finally faqat tozalash uchun. return/break/continue yozmang.

  4. Resurs uchun with. try/finally — faqat maxsus holatlarda.

  5. finally dagi xatoni yuting. Asl xato saqlansin.

  6. Ochishdan keyin darhol try. Yoki with ... as a, ... as b.

  7. Dinamik resurslar uchun ExitStack.

  8. Tranzaksiya naqshi: except → bekor, else → tasdiqla, finally → yop.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
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
  1. 2
  2. 1 — istisno yutildi
  3. 1 — qiymat saqlangan
  4. [1, 2] — havola
  5. f keyin 1 — else bajarilmaydi
  6. SyntaxError — else except siz
  7. 0 1 2
  8. f e
  9. TypeError ValueError
  10. f 0
  11. davom
  12. davom — __exit__ True

Vazifa 2: Xatolarni tuzating

python
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 True
Javoblar
python
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:

  1. @contextmanager bilan tranzaksiya
  2. Muvaffaqiyat → commit, xato → rollback
  3. finally da ulanishni yopish
  4. Ichma-ich tranzaksiyalar (savepoint)
  5. Faqat ma'lum xatolarda rollback
  6. Statistika: commit/rollback soni

Vazifa 4: finally tekshiruvchisi

Vosita yozing (AST bilan):

  1. finally da return larni topsin
  2. finally da break/continue
  3. finally da xato berishi mumkin bo'lgan chaqiruvlar
  4. try bloki 5 qatordan uzun bo'lsa
  5. else ishlatilmagan joylarni (tavsiya)
  6. try/finally o'rniga with mumkin bo'lgan joylarni

Vazifa 5: Resurs hovuzi

  1. ExitStack bilan dinamik resurslar
  2. Ochishda xato → oldingilarini yopish
  3. Yopishda xato → jurnalga, qolganlarini yopish
  4. Timeout bilan ochish
  5. Statistika: ochilgan/yopilgan/oqib ketgan
  6. Kontekst menejeri sifatida

Vazifa 6: Qayta urinish + tozalash

  1. Har urinishda resurs ochiladi/yopiladi
  2. finally da har urinish vaqti o'lchanadi
  3. Muvaffaqiyat → else da natija
  4. Barcha urinishlar xato → yakuniy istisno
  5. Orqaga qaytarish (agar qisman bajarilgan bo'lsa)
  6. 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

python
# 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:

python
# ❌ 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:

python
# ❌ 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:

python
finally:
    f.close()                       # ⚠️ bu ham xato berishi mumkin
                                    #    → asl xato yashirinadi

3. PEP 343 (2005) motivatsiyasi

Guido va Nick Coghlan yozdi:

"This PEP adds a new statement with to the Python language to make it possible to factor out standard uses of try/finally statements."

Uch maqsad:

  1. Takrorlanishni yo'q qilish — tozalash mantiqi bir joyda
  2. Xatolarni oldini olish — f = open() try dan tashqarida
  3. O'qilishni yaxshilash — niyat ko'rinadi

4. with nima beradi

python
with open(yol) as f:
    ishla(f)

Aslida:

python
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:

python
with ochish("a") as a, ochish("b") as b:    # ⭐ b xato bersa a yopiladi
    ...

b) __exit__ istisnoni ko'radi:

python
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:

python
with contextlib.suppress(FileNotFoundError):
    os.remove(yol)                  # ⭐ 2 qator

d) Qayta ishlatiladigan mantiq:

python
@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:

python
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:

python
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:

rust
{
    let f = File::open(yol)?;       // ⭐ hech qanday `with` kerak emas
    ishla(&f);
}                                   // ⭐ f bu yerda AVTOMATIK yopiladi

Egalik tizimi tufayli obyekt qamrovdan chiqqanda avtomatik tozalanadi. Dasturchi hech narsa yozmaydi.

Go — defer:

go
f, err := os.Open(yol)
if err != nil { return err }
defer f.Close()                     // ⭐ funksiya oxirida
ishla(f)

defer — funksiya oxirida, blok emas. Tsiklda muammo:

go
for _, y := range yollar {
    f, _ := os.Open(y)
    defer f.Close()                 // ⚠️ HAMMASI funksiya oxirida!
}

Java:

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:

python
# 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:

python
@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/finally

10. Xulosa

with qo'shildi, chunki try/finally:

  1. Takrorlanardi — har resursda bir xil naqsh
  2. To'g'ri yozish qiyin — f = open() joyi, ichma-ich bloklar
  3. Istisno haqida bilmaydi — finally xato bo'lganini ko'rmaydi
  4. 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:

  1. else — try blokini qisqartiradi va xatoni yashirmaydi. try ichiga faqat xato berishi mumkin bo'lgan qatorni qo'ying; muvaffaqiyat kodi else ga. Aks holda else dagi tasodifiy ValueError except ValueError ga tushib, noto'g'ri xabar beriladi.

  2. finally — har doim bajariladi, hatto return va ushlanmagan istisnoda ham. Lekin finally da return, break yoki continue yozmang: ular saqlangan qiymatni yoki ko'tarilayotgan istisnoni jimgina yo'q qiladi. finally faqat tozalash uchun — va uning ichidagi xatoni ham yutib, jurnalga yozing, aks holda asl sabab yashirinadi.

  3. Resurslar uchun with — try/finally dan yaxshiroq. U ochish xatosini avtomatik hal qiladi, bir nechta resursni bir qatorda boshqaradi (ExitStack bilan 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.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
9.3-dars: else va finally — IlmHamroh