IlmHamroh
Python kursi/Funksiyalar7/14-dars35 daqiqa
Mundarija (21)

7.7-dars: return — chuqur

7-QISM — FUNKSIYALAR · 7-dars


1. Kirish va motivatsiya

return oddiy ko'rinadi:

python
def kvadrat(x):
    return x ** 2

Lekin uning atrofida ko'p nozik savol bor:

python
def f():
    return 1, 2                 # nechta qiymat qaytadi?

def g():
    try:
        return 1
    finally:
        return 2                # nima qaytadi?

def h():
    for x in [1, 2, 3]:
        return x                # sikl to'xtaydimi?

def k():
    yield 1
    return 2                    # bu nima qiladi?

Va eng ko'p uchraydigan chalkashlik:

python
def toifa(ball):
    if ball >= 90:
        return "a'lo"
    elif ball >= 70:
        return "yaxshi"
    # else kerakmi?

Bu darsda:

  • return semantikasi va bajarilish oqimi
  • Bir nechta qiymat — aslida bitta tuple
  • try/finally bilan nozik o'zaro ta'sir
  • Erta qaytish (guard clause) uslubi
  • return vs yield — generator funksiyalari
  • None semantikasi va tur ko'rsatkichlari

2. Nazariya — chuqur tushuntirish

2.1. Semantika

return ikki ish qiladi:

  1. Funksiyani darhol to'xtatadi
  2. Qiymatni chaqiruvchiga qaytaradi
python
def f():
    print("bir")
    return 1
    print("ikki")               # ❌ bajarilmaydi

Uch shakl:

python
def a(): return          # None
def b(): return None     # None
def c(): pass            # None (return yo'q)

Bytecode darajasida ham bir xil:

python
import dis
dis.dis("def f(): pass")
#   LOAD_CONST None
#   RETURN_VALUE

Aniq instruksiya nomlari versiyaga bog'liq: Python 3.12–3.13 bu ikkisini bitta RETURN_CONST ga birlashtirgan edi, 3.14 esa yana LOAD_CONST + RETURN_VALUE ga qaytdi. Muhimi o'zgarmaydi — uchala shakl ham bir xil bayt-kodga aylanadi.

Python har funksiya oxiriga avtomatik return None qo'yadi.

Har qanday joyda:

python
def f(x):
    if x:
        for i in range(10):
            if i > 5:
                return i        # sikl va shartdan chiqib ketadi
    while True:
        return "cheksiz sikldan"

return — barcha ichma-ich bloklardan chiqadi (break faqat bittasidan).

2.2. Bir nechta qiymat — aslida tuple

python
def min_max(r):
    return min(r), max(r)       # ⭐ tuple qaytadi

natija = min_max([3, 1, 4])
print(natija)                   # (1, 4)
print(type(natija))             # <class 'tuple'>

a, b = min_max([3, 1, 4])       # ochish (6.5-dars)

Python funksiyalari "bir nechta qiymat qaytarmaydi" — ular bitta tuple qaytaradi, va biz uni ochamiz.

Qavs ixtiyoriy:

python
return 1, 2                     # ✅
return (1, 2)                   # ✅ bir xil

Bitta element:

python
return 1,                       # ⚠️ (1,) — tuple!
return (1,)                     # ⚠️ bir xil
return 1                        # ✅ int

Tasodifiy vergul — jimgina xato manbai (6.5-dars).

Qachon nomli natija:

3-4 qiymatdan ko'p bo'lsa, tuple chalkash bo'ladi:

python
def tahlil(matn):
    return len(matn), len(matn.split()), matn.count("."), ...
    # ⚠️ [3] nima edi?

Yaxshiroq — NamedTuple (6.6-dars):

python
from typing import NamedTuple

class Tahlil(NamedTuple):
    belgilar: int
    sozlar: int
    jumlalar: int


def tahlil(matn) -> Tahlil:
    return Tahlil(len(matn), len(matn.split()), matn.count("."))


n = tahlil("Salom. Dunyo.")
n.sozlar                        # ✅ ravshan
n[1]                            # ✅ ham ishlaydi
a, b, c = n                     # ✅ ochish ham

Yoki dataclass:

python
@dataclass
class Natija:
    muvaffaqiyat: bool
    qiymat: Any = None
    xato: str | None = None

dict qaytarish — kam tavsiya:

python
def f():
    return {"a": 1, "b": 2}     # ⚠️ kalitlar tekshirilmaydi

IDE yordam bermaydi, xato yozilgan kalit ish vaqtida chiqadi.

2.3. Erta qaytish (guard clause)

Ichma-ich if:

python
def qayta_ishla(malumot):
    if malumot is not None:
        if len(malumot) > 0:
            if tekshir(malumot):
                natija = hisobla(malumot)
                return natija
            else:
                return None
        else:
            return None
    else:
        return None

Erta qaytish:

python
def qayta_ishla(malumot):
    if malumot is None:
        return None
    if not malumot:
        return None
    if not tekshir(malumot):
        return None
    return hisobla(malumot)

Afzalliklari:

  • Ichma-ichlik yo'q (o'ngga surilish yo'q)
  • Har shart o'z javobiga yaqin
  • "Asosiy yo'l" oxirida, aniq ko'rinadi
  • Yangi shart qo'shish oson

else kerak emas:

python
def toifa(ball):
    if ball >= 90:
        return "a'lo"
    if ball >= 70:              # ✅ elif kerak emas
        return "yaxshi"
    if ball >= 50:
        return "qoniqarli"
    return "qoniqarsiz"         # ✅ else kerak emas

return chiqib ketgani uchun keyingi if faqat oldingisi bajarilmaganda tekshiriladi.

Lekin elif ba'zan aniqroq:

python
# Mantiqiy bog'liqlikni ko'rsatadi
if a:
    return 1
elif b:                         # "a bo'lmasa VA b bo'lsa"
    return 2

Bu — uslub masalasi. ruff/pylint no-else-return qoidasi else ni olib tashlashni taklif qiladi.

Xato holatlarini oldinga:

python
def bol(a, b):
    if b == 0:
        raise ValueError("nolga bo'lish")        # ✅ oldinda
    return a / b

2.4. try/finally bilan

finally DOIM bajariladi — hatto return dan keyin ham:

python
def f():
    try:
        return 1
    finally:
        print("finally")        # ✅ bajariladi

f()                             # "finally" chiqadi, keyin 1 qaytadi

Tartib:

  1. return 1 — qaytariladigan qiymat hisoblanadi va saqlanadi
  2. finally bajariladi
  3. Saqlangan qiymat qaytariladi

finally da return — asl qiymatni BOSIB O'TADI:

python
def f():
    try:
        return 1
    finally:
        return 2                # ⚠️

f()                             # 2

Istisnoni ham yutadi:

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

f()                             # "yutildi" — xato yo'q!

Qoida: finally da return yozmang. Bu — ruff B012 ogohlantirishi.

finally o'zgaruvchini o'zgartirsa:

python
def f():
    x = [1]
    try:
        return x                # x obyektiga havola saqlanadi
    finally:
        x.append(2)             # ⚠️ o'sha obyekt o'zgaradi

f()                             # [1, 2]
python
def g():
    x = 1
    try:
        return x                # qiymat (1) saqlanadi
    finally:
        x = 99                  # ✅ yangi obyekt — ta'sir qilmaydi

g()                             # 1

Bu — 7.2-darsdagi yorliq/obyekt farqi.

try/except bilan:

python
def f():
    try:
        return 1 / 0
    except ZeroDivisionError:
        return "xato"
    finally:
        print("tozalash")

f()                             # "tozalash" chiqadi, keyin "xato"

2.5. return vs yield

Funksiyada yield bo'lsa — u generator funksiyasi bo'ladi:

python
def oddiy():
    return 1

def generator():
    yield 1

type(oddiy())                   # <class 'int'>
type(generator())               # <class 'generator'>

yield bo'lsa, return — boshqacha ishlaydi:

python
def g():
    yield 1
    yield 2
    return 3                    # ⚠️ qiymat StopIteration ga o'raladi

gen = g()
next(gen)                       # 1
next(gen)                       # 2
next(gen)                       # ❌ StopIteration: 3

return qiymati iteratsiyada ko'rinmaydi:

python
list(g())                       # [1, 2]  — 3 yo'q

Uni olish uchun:

python
gen = g()
try:
    while True:
        next(gen)
except StopIteration as x:
    natija = x.value            # 3

Yoki yield from:

python
def tashqi():
    natija = yield from g()     # ⭐ return qiymatini oladi
    print(natija)               # 3

Python 3.3 dan oldin generatorlarda qiymatli return taqiqlangan edi (PEP 380 o'zgartirdi).

Bo'sh return — generatorni to'xtatadi:

python
def g(n):
    for i in range(n):
        if i > 3:
            return              # ✅ to'xtatadi
        yield i

list(g(10))                     # [0, 1, 2, 3]

2.6. None semantikasi

Uch xil ma'no:

python
# 1. "Natija yo'q" — normal holat
def topish(r, x):
    for y in r:
        if y == x:
            return y
    return None                 # topilmadi — normal

# 2. "Yon ta'sir" — qiymat kutilmaydi
def saqla(malumot) -> None:
    fayl.write(malumot)

# 3. ⚠️ Xato — return unutilgan
def ikkilash(r):
    [x * 2 for x in r]          # ⚠️ None qaytadi

Tur ko'rsatkichlari farqni ko'rsatadi:

python
def f() -> None: ...            # hech qachon qiymat qaytarmaydi
def f() -> int | None: ...      # ba'zan None
def f() -> int: ...             # doim int (None bo'lsa — xato)

mypy buni tekshiradi:

python
def f() -> int:
    if shart:
        return 1
    # mypy: Missing return statement

None yoki istisno?

python
# None — "normal, lekin natija yo'q"
d.get(kalit)                    # None
re.match(naqsh, matn)           # None
next(it, None)                  # None

# Istisno — "kutilmagan holat"
d[kalit]                        # KeyError
int("abc")                      # ValueError
r[100]                          # IndexError

Qoida: agar "natija yo'q" kutilgan bo'lsa — None. Agar bu xato bo'lsa — istisno.

Sentinel (7.3-dars) — None ham yaroqli qiymat bo'lsa:

python
_YOQ = object()

def ol(d, kalit, sukut=_YOQ):
    if kalit in d:
        return d[kalit]
    if sukut is _YOQ:
        raise KeyError(kalit)
    return sukut

2.7. Nozik holatlar

1. return sikl ichida — sikl to'xtaydi:

python
def birinchi_juft(r):
    for x in r:
        if x % 2 == 0:
            return x            # ✅ butun funksiyadan chiqadi
    return None

break faqat siklni to'xtatadi, return — funksiyani.

2. return with ichida — __exit__ chaqiriladi:

python
def f(yol):
    with open(yol) as fayl:
        return fayl.read()      # ✅ fayl yopiladi

3. Rekursiyada return unutish:

python
def fib(n):
    if n < 2:
        return n
    fib(n - 1) + fib(n - 2)     # ❌ return yo'q → None

4. Shartli qaytarish to'liq emas:

python
def f(x):
    if x > 0:
        return "musbat"
    # ⚠️ x <= 0 bo'lsa None

mypy --strict buni topadi.

5. return ifodada:

python
return x if shart else y        # ✅
return [f(i) for i in r]        # ✅
return (yield)                  # ⚠️ generator — kam ishlatiladi

6. Bir nechta return — muammomi?

Eski "structured programming" qoidasi: "bir kirish, bir chiqish".

Zamonaviy Pythonda — yo'q. Erta qaytish o'qilishni yaxshilaydi. Muhimi:

  • Har return aniq bo'lsin
  • Funksiya qisqa bo'lsin
  • Tozalash with/finally bilan bo'lsin

3. Tez ma'lumotnoma

Semantika

python
return               → None
return None          → None
(return yo'q)        → None
return 1, 2          → (1, 2) TUPLE ⭐
return 1,            → (1,) ⚠️ vergul!

return DARHOL to'xtatadi — barcha sikl va shartdan chiqadi

Bir nechta qiymat

python
def f(): return min(r), max(r)      tuple
a, b = f()                          ochish

3-4 dan ko'p → NamedTuple yoki dataclass

Erta qaytish (guard clause)

python
def f(x):
    if xato_holat: return None      ✅ oldinga
    if boshqa_xato: return None
    return asosiy_natija            ✅ oxirida

else/elif KERAK EMAS — return chiqib ketadi

try/finally

python
try: return 1
finally: print("x")     → "x" chiqadi, keyin 1

try: return 1
finally: return 2       → 2  ⚠️ bosib o'tadi

try: raise X
finally: return 1       → 1  ⚠️ ISTISNO YUTILADI

⭐ finally da return YOZMANG (ruff B012)

return vs yield

python
def g():
    yield 1
    return 3            → StopIteration.value = 3
list(g())               → [1]  (3 yo'q)
x = yield from g()      → x == 3  ⭐

return (bo'sh)          generatorni to'xtatadi

None semantikasi

python
-> None             hech qachon qiymat qaytarmaydi
-> int | None       ba'zan None (normal)
-> int              doim int (None — xato)

None:     "natija yo'q" KUTILGAN   (d.get, re.match)
Istisno:  "natija yo'q" XATO        (d[k], int("abc"))

4. Batafsil misollar

Misol 1 — Semantika va bir nechta qiymat

python
"""return ning barcha shakllari."""

import dis
from typing import NamedTuple
from dataclasses import dataclass

print("=== 1. Uch shakl ===")


def a(): return
def b(): return None
def c(): pass


for f, izoh in [(a, "return"), (b, "return None"), (c, "pass")]:
    print(f"  def f(): {izoh:<14} → {f()!r}")

print(f"\n  Bytecode bir xil:")
for kod in ["def f(): pass", "def f(): return", "def f(): return None"]:
    kodobj = compile(kod, "<t>", "exec").co_consts[0]
    instruksiyalar = [i.opname for i in dis.get_instructions(kodobj)]
    print(f"    {kod:<26} {instruksiyalar}")


print("\n=== 2. return darhol to'xtatadi ===")


def chuqur(x):
    if x > 0:
        for i in range(10):
            for j in range(10):
                if i * j > x:
                    return (i, j)       # ⭐ IKKALA sikldan ham chiqadi
    return None


print(f"  Ichma-ich sikl ichidan qaytish:")
for x in [5, 20, 50, -1]:
    print(f"    chuqur({x:>3}) → {chuqur(x)}")

print(f"\n  break bilan solishtiring:")


def break_bilan(x):
    natija = None
    for i in range(10):
        for j in range(10):
            if i * j > x:
                natija = (i, j)
                break                   # ⚠️ faqat ICHKI sikl
        if natija:
            break                       # ⚠️ tashqi sikl uchun alohida
    return natija


print(f"    break_bilan(20) = {break_bilan(20)}   (2 ta break kerak bo'ldi)")
print(f"    chuqur(20)      = {chuqur(20)}   (1 ta return)")


print("\n=== 3. ⭐ Bir nechta qiymat ===")


def min_max(r):
    return min(r), max(r)


natija = min_max([3, 1, 4, 1, 5])
print(f"  def f(r): return min(r), max(r)\n")
print(f"    natija = {natija}")
print(f"    type   = {type(natija).__name__}   ⭐ TUPLE")
print(f"    a, b = f(r)  →  a={natija[0]}, b={natija[1]}")

print(f"\n  Qavs ixtiyoriy:")


def q1(): return 1, 2
def q2(): return (1, 2)


print(f"    return 1, 2    → {q1()}")
print(f"    return (1, 2)  → {q2()}")

print(f"\n  ⚠️ Bitta element va vergul:")


def v1(): return 1
def v2(): return 1,
def v3(): return (1,)


for f, kod in [(v1, "return 1"), (v2, "return 1,"), (v3, "return (1,)")]:
    n = f()
    print(f"    {kod:<16} → {n!r:<8} ({type(n).__name__})")

print(f"\n  ⚠️ Tasodifiy vergul — jimgina xato:")
print(f"     x = f()       →  (1,) o'rniga 1 kutilgan edi")
print(f"     x + 1         →  ❌ TypeError")


print("\n=== 4. Ko'p qiymat — nomlangan natija ===")


def tahlil_tuple(matn):
    """⚠️ 5 ta qiymat — [3] nima edi?"""
    sozlar = matn.split()
    return (len(matn), len(sozlar), matn.count("."),
            len(set(sozlar)), sum(len(s) for s in sozlar) / len(sozlar))


class Tahlil(NamedTuple):
    """✅ Nomlangan maydonlar."""
    belgilar: int
    sozlar: int
    jumlalar: int
    noyob: int
    ortacha_uzunlik: float


def tahlil_named(matn) -> Tahlil:
    sozlar = matn.split()
    return Tahlil(
        belgilar=len(matn),
        sozlar=len(sozlar),
        jumlalar=matn.count("."),
        noyob=len(set(sozlar)),
        ortacha_uzunlik=sum(len(s) for s in sozlar) / len(sozlar),
    )


MATN = "Python kuchli. Python oddiy. Python tez."

t1 = tahlil_tuple(MATN)
t2 = tahlil_named(MATN)

print(f"  Matn: {MATN!r}\n")
print(f"  ⚠️ tuple bilan:")
print(f"    {t1}")
print(f"    t[3] = {t1[3]}   ← nima edi?\n")

print(f"  ✅ NamedTuple bilan:")
print(f"    {t2}")
print(f"    t.noyob = {t2.noyob}   ← ravshan")

print(f"\n  NamedTuple imkoniyatlari:")
print(f"    t[3]           = {t2[3]}      (indeks ham ishlaydi)")
print(f"    a, b, *_ = t   = {t2[0]}, {t2[1]}  (ochish ham)")
print(f"    t._asdict()    = {dict(list(t2._asdict().items())[:2])}...")
print(f"    t._replace()   = {t2._replace(sozlar=99).sozlar}")


print("\n=== 5. Natija turlari ===")


@dataclass
class Natija:
    """Muvaffaqiyat yoki xato."""
    muvaffaqiyat: bool
    qiymat: object = None
    xato: str | None = None

    @classmethod
    def ok(cls, qiymat):
        return cls(True, qiymat)

    @classmethod
    def xato_bilan(cls, xabar):
        return cls(False, xato=xabar)

    def __bool__(self):
        return self.muvaffaqiyat


def xavfsiz_bol(a, b) -> Natija:
    if b == 0:
        return Natija.xato_bilan("nolga bo'lish")
    if not isinstance(a, (int, float)):
        return Natija.xato_bilan(f"a son emas: {type(a).__name__}")
    return Natija.ok(a / b)


SINOVLAR = [(10, 2), (10, 0), ("a", 2), (7, 3)]

print(f"  {'Chaqiruv':<20} {'Natija':<40} {'bool'}")
print("  " + "─" * 68)
for a, b in SINOVLAR:
    n = xavfsiz_bol(a, b)
    print(f"  bol({a!r}, {b!r}){'':<{max(0, 12 - len(repr(a)) - len(repr(b)))}} "
          f"{str(n):<40} {bool(n)}")

print(f"\n  Ishlatish:")
print(f"""
    n = xavfsiz_bol(10, 0)
    if n:
        print(n.qiymat)
    else:
        print(f"Xato: {{n.xato}}")
""")

n = xavfsiz_bol(10, 0)
if n:
    print(f"    Qiymat: {n.qiymat}")
else:
    print(f"    Xato: {n.xato}")


print("\n=== 6. Nima qaytarish kerak ===")

print("""
  ┌────────────────────────────┬──────────────────────────────────┐
  │ Holat                      │ Qaytarish                        │
  ├────────────────────────────┼──────────────────────────────────┤
  │ Bitta qiymat               │ Qiymatning o'zi                  │
  │ 2-3 bog'liq qiymat         │ tuple (ochiladi)                 │
  │ 3+ qiymat                  │ NamedTuple ⭐                     │
  │ Muvaffaqiyat/xato          │ dataclass yoki istisno           │
  │ Ixtiyoriy natija           │ T | None                         │
  │ Yon ta'sir                 │ None (-> None)                   │
  │ Ko'p element               │ list / generator                 │
  │ Kalit → qiymat             │ dict                             │
  │ Dinamik struktura          │ dict (⚠️ IDE yordam bermaydi)    │
  └────────────────────────────┴──────────────────────────────────┘
""")

Natijaning muhim qismi:

text
=== 1. Uch shakl ===
  def f(): return         → None
  def f(): return None    → None
  def f(): pass           → None

  Bytecode bir xil:
    def f(): pass              ['RESUME', 'LOAD_CONST', 'RETURN_VALUE']
    def f(): return            ['RESUME', 'LOAD_CONST', 'RETURN_VALUE']
    def f(): return None       ['RESUME', 'LOAD_CONST', 'RETURN_VALUE']

=== 3. ⭐ Bir nechta qiymat ===
    natija = (1, 5)
    type   = tuple   ⭐ TUPLE

  ⚠️ Bitta element va vergul:
    return 1         → 1        (int)
    return 1,        → (1,)     (tuple)

=== 4. Ko'p qiymat — nomlangan natija ===
  ⚠️ tuple bilan:
    (40, 6, 3, 4, 5.833333333333333)
    t[3] = 4   ← nima edi?

  ✅ NamedTuple bilan:
    Tahlil(belgilar=40, sozlar=6, jumlalar=3, noyob=4, ortacha_uzunlik=5.833333333333333)
    t.noyob = 4   ← ravshan

Nima ko'rsatdi: 2.1, 2.2-bo'limlar.

Misol 2 — Erta qaytish va try/finally

python
"""Guard clause uslubi va finally nozikliklari."""

print("=== 1. Ichma-ich if vs erta qaytish ===")


def qayta_ishla_yomon(malumot, sozlamalar):
    """❌ 4 daraja ichma-ichlik."""
    if malumot is not None:
        if len(malumot) > 0:
            if sozlamalar is not None:
                if sozlamalar.get("yoqilgan"):
                    natija = sum(malumot)
                    return natija
                else:
                    return None
            else:
                return None
        else:
            return None
    else:
        return None


def qayta_ishla_yaxshi(malumot, sozlamalar):
    """✅ Erta qaytish."""
    if malumot is None:
        return None
    if not malumot:
        return None
    if sozlamalar is None:
        return None
    if not sozlamalar.get("yoqilgan"):
        return None
    return sum(malumot)


SINOVLAR = [
    ([1, 2, 3], {"yoqilgan": True}),
    ([1, 2, 3], {"yoqilgan": False}),
    ([], {"yoqilgan": True}),
    (None, {"yoqilgan": True}),
    ([1, 2], None),
]

print(f"  {'Kirish':<40} {'Yomon':<10} {'Yaxshi'}")
print("  " + "─" * 62)
for m, s in SINOVLAR:
    a = qayta_ishla_yomon(m, s)
    b = qayta_ishla_yaxshi(m, s)
    belgi = "✅" if a == b else "❌"
    print(f"  {str((m, s))[:38]:<40} {str(a):<10} {belgi} {b}")

print(f"\n  Kod chuqurligi:")
import inspect
for f in [qayta_ishla_yomon, qayta_ishla_yaxshi]:
    manba = inspect.getsource(f)
    maks_daraja = max(
        (len(q) - len(q.lstrip())) // 4
        for q in manba.splitlines() if q.strip()
    )
    print(f"    {f.__name__:<24} maksimal ichma-ichlik: {maks_daraja}")


print("\n=== 2. else kerak emas ===")


def toifa_else_bilan(ball):
    if ball >= 90:
        return "a'lo"
    elif ball >= 70:
        return "yaxshi"
    elif ball >= 50:
        return "qoniqarli"
    else:
        return "qoniqarsiz"


def toifa_else_siz(ball):
    if ball >= 90:
        return "a'lo"
    if ball >= 70:
        return "yaxshi"
    if ball >= 50:
        return "qoniqarli"
    return "qoniqarsiz"


BALLAR = [95, 85, 75, 55, 30]
print(f"  {'Ball':>6} {'else bilan':<14} {'else siz'}")
print("  " + "─" * 36)
for ball in BALLAR:
    a, b = toifa_else_bilan(ball), toifa_else_siz(ball)
    print(f"  {ball:>6} {a:<14} {'✅' if a == b else '❌'} {b}")

print("""
  ⭐ return chiqib ketgani uchun `else` ortiqcha.

  ⚠️ Lekin ba'zan `elif` mantiqiy bog'liqlikni ko'rsatadi —
     bu uslub masalasi. ruff qoidasi: RET505 (no-else-return).
""")


print("\n=== 3. ⚠️ try/finally ===")


def f1():
    try:
        return 1
    finally:
        print("      finally bajarildi")


def f2():
    try:
        return 1
    finally:
        return 2                    # ⚠️


def f3():
    try:
        raise ValueError("xato")
    finally:
        return "yutildi"            # ⚠️


def f4():
    try:
        return 1
    except Exception:
        return 2
    finally:
        print("      tozalash")


print(f"  1. try: return 1 / finally: print(...)")
print(f"     → {f1()}\n")

print(f"  2. try: return 1 / finally: return 2")
print(f"     → {f2()}   ⚠️ finally BOSIB O'TDI\n")

print(f"  3. try: raise / finally: return 'yutildi'")
print(f"     → {f3()!r}   ⚠️ ISTISNO YO'QOLDI\n")

print(f"  4. try/except/finally:")
print(f"     → {f4()}")

print("""
  ⭐ Bajarilish tartibi:
     1. return X — X hisoblanadi va SAQLANADI
     2. finally bajariladi
     3. Saqlangan qiymat qaytariladi

  ⚠️ finally da return yoki raise — asl natijani BOSIB O'TADI.
     ruff B012 buni ogohlantiradi.
""")


print("\n=== 4. finally va o'zgaruvchan obyekt ===")


def royxat_bilan():
    x = [1]
    try:
        return x                    # obyektga HAVOLA saqlanadi
    finally:
        x.append(2)                 # ⚠️ o'sha obyekt o'zgaradi


def son_bilan():
    x = 1
    try:
        return x                    # QIYMAT saqlanadi
    finally:
        x = 99                      # ✅ yangi obyekt


def royxat_qayta_boglash():
    x = [1]
    try:
        return x
    finally:
        x = [99]                    # ✅ qayta bog'lash — ta'sir yo'q


print(f"  {'Funksiya':<26} {'Natija'}")
print("  " + "─" * 42)
print(f"  {'return x; x.append(2)':<26} {royxat_bilan()}   ⚠️ o'zgardi")
print(f"  {'return x; x = 99':<26} {son_bilan()}   ✅")
print(f"  {'return x; x = [99]':<26} {royxat_qayta_boglash()}   ✅")

print("""
  ⭐ return OBYEKTGA HAVOLANI saqlaydi (7.2-dars).
     • Obyektni o'zgartirish → natijaga ta'sir qiladi
     • Yorliqni qayta bog'lash → ta'sir qilmaydi
""")


print("\n=== 5. Bajarilish tartibi ===")

kuzatuv = []


def kuzat(nom, qiymat=None):
    kuzatuv.append(nom)
    return qiymat


def murakkab():
    kuzat("boshlandi")
    try:
        kuzat("try")
        return kuzat("return ifodasi", "natija")
    except Exception:
        kuzat("except")
        return "xato"
    else:
        kuzat("else")
    finally:
        kuzat("finally")


kuzatuv.clear()
natija = murakkab()

print(f"  Natija: {natija!r}\n")
print(f"  Bajarilish tartibi:")
for i, q in enumerate(kuzatuv, 1):
    print(f"    {i}. {q}")

print("""
  ⚠️ `else` bajarilmadi — chunki `try` da `return` bor.
     `else` faqat try MUVAFFAQIYATLI TUGAGANDA (return siz) bajariladi.
""")

kuzatuv.clear()


def else_bilan():
    try:
        kuzat("try")
    except Exception:
        kuzat("except")
    else:
        kuzat("else")               # ✅ bajariladi
        return "else dan"
    finally:
        kuzat("finally")


natija = else_bilan()
print(f"  else_bilan() = {natija!r}")
print(f"  Tartib: {kuzatuv}")


print("\n=== 6. with bilan ===")

import io


def oqi(matn):
    with io.StringIO(matn) as f:
        return f.read()             # ✅ __exit__ chaqiriladi


class Kuzatuvchi:
    def __enter__(self):
        print("      __enter__")
        return self

    def __exit__(self, *args):
        print("      __exit__ (return dan keyin ham!)")
        return False


def with_bilan():
    with Kuzatuvchi():
        print("      tana")
        return "natija"


print(f"  with bloki ichida return:")
natija = with_bilan()
print(f"  → {natija!r}")

print(f"\n  Fayl bilan:")
print(f"    oqi('salom') = {oqi('salom')!r}   ✅ fayl yopildi")

print("""
  ⭐ return `with` blokidan chiqishda __exit__ ni chaqiradi.
     Resurs to'g'ri bo'shatiladi.
""")


print("\n=== 7. ⚠️ return unutish ===")


def fib_yomon(n):
    """❌ Rekursiyada return unutilgan."""
    if n < 2:
        return n
    fib_yomon(n - 1) + fib_yomon(n - 2)


def fib_yaxshi(n):
    if n < 2:
        return n
    return fib_yaxshi(n - 1) + fib_yaxshi(n - 2)


print(f"  fib_yomon(1)  = {fib_yomon(1)}   (asosiy holat — return bor)")
print(f"  fib_yomon(2)  = {fib_yomon(2)}   ⚠️ 1 + 0 hisoblandi, lekin qaytarilmadi")
try:
    fib_yomon(5)
except TypeError as e:
    print(f"  fib_yomon(5)  → ❌ TypeError: {e}")
    print(f"                  ⭐ None ichkarida hisobga qo'shildi: fib_yomon(3) = None + 1")
print(f"  fib_yaxshi(5) = {fib_yaxshi(5)}   ✅")


def toliqsiz(x):
    """⚠️ x <= 0 bo'lsa None."""
    if x > 0:
        return "musbat"


print(f"\n  toliqsiz(5)  = {toliqsiz(5)!r}")
print(f"  toliqsiz(-5) = {toliqsiz(-5)!r}   ⚠️ None")

print("""
  ⭐ mypy --strict bu xatolarni topadi:
     "Missing return statement"
""")

Natijaning muhim qismi:

text
=== 1. Ichma-ich if vs erta qaytish ===
  Kod chuqurligi:
    qayta_ishla_yomon        maksimal ichma-ichlik: 5
    qayta_ishla_yaxshi       maksimal ichma-ichlik: 2

=== 3. ⚠️ try/finally ===
  2. try: return 1 / finally: return 2
     → 2   ⚠️ finally BOSIB O'TDI

  3. try: raise / finally: return 'yutildi'
     → 'yutildi'   ⚠️ ISTISNO YO'QOLDI

=== 4. finally va o'zgaruvchan obyekt ===
  Funksiya                   Natija
  ──────────────────────────────────────────
  return x; x.append(2)      [1, 2]   ⚠️ o'zgardi
  return x; x = 99           1   ✅
  return x; x = [99]         [1]   ✅

=== 5. Bajarilish tartibi ===
    1. boshlandi
    2. try
    3. return ifodasi
    4. finally

Nima ko'rsatdi: 2.3, 2.4-bo'limlar.

Misol 3 — return vs yield

python
"""Generator funksiyalarida return."""

import inspect

print("=== 1. yield funksiyani generatorga aylantiradi ===")


def oddiy():
    return 1


def generator():
    yield 1


def ikkalasi():
    yield 1
    return 2                        # ⚠️ generator bo'lib qoladi


print(f"  {'Funksiya':<14} {'type(f())':<22} {'Generatormi'}")
print("  " + "─" * 54)
for f in [oddiy, generator, ikkalasi]:
    natija = f()
    gen = inspect.isgeneratorfunction(f)
    print(f"  {f.__name__:<14} {type(natija).__name__:<22} {gen}")

print(f"\n  ⭐ Tanada BITTA yield bo'lsa ham — generator funksiyasi")


print("\n=== 2. ⚠️ Generatorda return qiymati ===")


def g():
    yield 1
    yield 2
    return "yakuniy qiymat"


print(f"  def g():")
print(f"      yield 1")
print(f"      yield 2")
print(f"      return 'yakuniy qiymat'\n")

print(f"  list(g()) = {list(g())}   ⚠️ 'yakuniy qiymat' YO'Q\n")

print(f"  Qo'lda iteratsiya:")
gen = g()
for i in range(4):
    try:
        print(f"    next(gen) → {next(gen)!r}")
    except StopIteration as x:
        print(f"    next(gen) → StopIteration, value = {x.value!r}   ⭐")
        break

print(f"\n  Qiymatni olish:")
print(f"""
    gen = g()
    try:
        while True:
            next(gen)
    except StopIteration as x:
        natija = x.value            # 'yakuniy qiymat'
""")


print("\n=== 3. ⭐ yield from bilan ===")


def ichki():
    yield 1
    yield 2
    return "ichki natija"


def tashqi():
    natija = yield from ichki()     # ⭐ return qiymatini oladi
    print(f"      ichki qaytardi: {natija!r}")
    yield 3
    return "tashqi natija"


print(f"  def tashqi():")
print(f"      natija = yield from ichki()")
print(f"      yield 3\n")

gen = tashqi()
qiymatlar = []
try:
    while True:
        qiymatlar.append(next(gen))
except StopIteration as x:
    print(f"\n  Berilgan qiymatlar: {qiymatlar}")
    print(f"  Yakuniy natija: {x.value!r}")

print("""
  ⭐ `yield from` — ichki generatorning return qiymatini oladi.
     Bu PEP 380 (Python 3.3) da qo'shilgan.

     Undan oldin generatorlarda qiymatli return TAQIQLANGAN edi.
""")


print("\n=== 4. Bo'sh return — to'xtatish ===")


def cheklangan(n):
    for i in range(100):
        if i >= n:
            return                  # ✅ generatorni to'xtatadi
        yield i


def shart_bilan(r):
    for x in r:
        if x is None:
            return                  # to'xtatish
        if x < 0:
            continue                # o'tkazib yuborish
        yield x * 2


print(f"  cheklangan(5)  = {list(cheklangan(5))}")
print(f"  cheklangan(0)  = {list(cheklangan(0))}")

MALUMOT = [1, -2, 3, None, 5, 6]
print(f"\n  shart_bilan({MALUMOT})")
print(f"    = {list(shart_bilan(MALUMOT))}")
print(f"    ⭐ None da to'xtadi, manfiylar o'tkazildi")


print("\n=== 5. Generator vs oddiy funksiya ===")


def royxat_qaytaradi(n):
    """Oddiy funksiya — hammasi darhol."""
    natija = []
    for i in range(n):
        natija.append(i ** 2)
    return natija


def generator_beradi(n):
    """Generator — birma-bir."""
    for i in range(n):
        yield i ** 2


import sys
import time

N = 1_000_000

boshlandi = time.perf_counter()
r = royxat_qaytaradi(N)
vaqt_royxat = time.perf_counter() - boshlandi
hajm_royxat = sys.getsizeof(r)

boshlandi = time.perf_counter()
g = generator_beradi(N)
vaqt_gen = time.perf_counter() - boshlandi
hajm_gen = sys.getsizeof(g)

print(f"  {N:,} element:\n")
print(f"  {'Usul':<24} {'Yaratish':>12} {'Xotira':>14}")
print("  " + "─" * 54)
print(f"  {'return [...]':<24} {vaqt_royxat * 1000:>9.1f} ms {hajm_royxat:>12,} B")
print(f"  {'yield ...':<24} {vaqt_gen * 1000:>9.4f} ms {hajm_gen:>12,} B")
print(f"  {'Farq':<24} {vaqt_royxat / max(vaqt_gen, 1e-9):>9,.0f}x "
      f"{hajm_royxat / hajm_gen:>12,.0f}x")

print(f"\n  Yig'indi (ikkalasi ham bir xil):")
print(f"    sum(royxat_qaytaradi(1000)) = {sum(royxat_qaytaradi(1000)):,}")
print(f"    sum(generator_beradi(1000)) = {sum(generator_beradi(1000)):,}")

del r


print("\n=== 6. Aralash naqsh: erta to'xtash ===")


def qidir_royxat(malumot, shart):
    """❌ Barcha elementni tekshiradi."""
    natija = []
    for x in malumot:
        if shart(x):
            natija.append(x)
    return natija


def qidir_generator(malumot, shart):
    """✅ Dangasa — kerakligicha."""
    for x in malumot:
        if shart(x):
            yield x


chaqiruvlar = [0]


def qimmat_shart(x):
    chaqiruvlar[0] += 1
    return x % 1000 == 0


KATTA = range(100_000)

chaqiruvlar[0] = 0
birinchi = qidir_royxat(KATTA, qimmat_shart)[0]
royxat_chaqiruvlari = chaqiruvlar[0]

chaqiruvlar[0] = 0
birinchi = next(qidir_generator(KATTA, qimmat_shart))
gen_chaqiruvlari = chaqiruvlar[0]

print(f"  Birinchi mos elementni topish ({len(KATTA):,} elementdan):\n")
print(f"    return [...] → {royxat_chaqiruvlari:>8,} shart tekshiruvi")
print(f"    yield ...    → {gen_chaqiruvlari:>8,} shart tekshiruvi")
print(f"    Farq:          {royxat_chaqiruvlari / max(gen_chaqiruvlari, 1):>8,.0f}x")


print("\n=== 7. Qachon qaysi biri ===")

print("""
  ┌────────────────────────────┬──────────────────────────────────┐
  │ Holat                      │ Tanlov                           │
  ├────────────────────────────┼──────────────────────────────────┤
  │ Natija to'liq kerak        │ return list                      │
  │ Bir necha marta o'tish     │ return list                      │
  │ len(), indeks kerak        │ return list                      │
  │ Katta yoki cheksiz         │ yield ⭐                          │
  │ Erta to'xtash mumkin       │ yield ⭐                          │
  │ Quvur (pipeline)           │ yield ⭐                          │
  │ Resurs boshqaruvi (with)   │ yield ⭐ (6.17-dars)              │
  │ Kichik, oddiy              │ return list (soddaroq)           │
  └────────────────────────────┴──────────────────────────────────┘

  ⚠️ Generator funksiyasidan list qaytarish mumkin emas:

     def g():
         yield 1
         return [1, 2]      # ⚠️ [1,2] StopIteration.value ga tushadi
""")

Natijaning muhim qismi:

text
=== 2. ⚠️ Generatorda return qiymati ===
  list(g()) = [1, 2]   ⚠️ 'yakuniy qiymat' YO'Q

  Qo'lda iteratsiya:
    next(gen) → 1
    next(gen) → 2
    next(gen) → StopIteration, value = 'yakuniy qiymat'   ⭐

=== 5. Generator vs oddiy funksiya ===
  1,000,000 element:

  Usul                         Yaratish         Xotira
  ──────────────────────────────────────────────────────
  return [...]                  99.5 ms    8,448,728 B
  yield ...                   0.0203 ms          208 B
  Farq                         4,899x       40,619x

=== 6. Aralash naqsh: erta to'xtash ===
    return [...] →  100,000 shart tekshiruvi
    yield ...    →        1 shart tekshiruvi
    Farq:          100,000x

Nima ko'rsatdi: 2.5-bo'lim.

Misol 4 — Amaliy: parser va natija turlari

python
"""return dizayni — real vazifada."""

import re
from dataclasses import dataclass, field
from enum import Enum
from typing import NamedTuple, Any

print("=== Konfiguratsiya parseri ===\n")

XOM = """
# Server sozlamalari
host = db.wisar.uz
port = 5432
ssl = true
timeout = 30.5

# Noto'g'ri qatorlar
notogri qator
= qiymatsiz
kalit =

[bo'lim]
ichki = qiymat
"""


class XatoTuri(Enum):
    NAQSH = "naqsh mos kelmadi"
    BOSH_KALIT = "kalit bo'sh"
    BOSH_QIYMAT = "qiymat bo'sh"
    TUR = "turni aniqlab bo'lmadi"


@dataclass(frozen=True)
class Xato:
    qator_raqami: int
    qator: str
    turi: XatoTuri

    def __str__(self):
        return f"{self.qator_raqami:>3}: {self.turi.value} — {self.qator!r}"


class ParseNatijasi(NamedTuple):
    """⭐ Nomlangan natija — 4 ta qiymat."""
    sozlamalar: dict[str, Any]
    xatolar: list[Xato]
    bolimlar: list[str]
    qatorlar_soni: int

    @property
    def muvaffaqiyat(self) -> bool:
        return not self.xatolar

    def __bool__(self):
        return self.muvaffaqiyat


NAQSH = re.compile(r"^\s*([\w.]+)\s*=\s*(.*)$")
BOLIM = re.compile(r"^\s*\[([^\]]+)\]\s*$")


def turni_aniqla(qiymat: str) -> Any:
    """Satrni mos turga aylantiradi. Aniqlab bo'lmasa — satr."""
    past = qiymat.strip().lower()
    if past in ("true", "ha", "yes", "on"):
        return True
    if past in ("false", "yo'q", "no", "off"):
        return False
    if past in ("null", "none", "nil", ""):
        return None
    if qiymat.lstrip("-").isdigit():
        return int(qiymat)
    try:
        return float(qiymat)
    except ValueError:
        return qiymat.strip()


def parse(matn: str) -> ParseNatijasi:
    """Konfiguratsiyani parse qiladi.

    ⭐ Erta qaytish yo'q — barcha qatorni ko'rish kerak.
       Lekin ichki funksiyada guard clause ishlatiladi.
    """
    sozlamalar: dict[str, Any] = {}
    xatolar: list[Xato] = []
    bolimlar: list[str] = []
    joriy_bolim = ""

    qatorlar = matn.strip().splitlines()

    for i, qator in enumerate(qatorlar, 1):
        toza = qator.strip()

        # ⭐ Guard clause — o'tkazib yuboriladigan qatorlar
        if not toza:
            continue
        if toza.startswith("#"):
            continue

        # Bo'lim
        if (m := BOLIM.match(toza)):
            joriy_bolim = m.group(1)
            bolimlar.append(joriy_bolim)
            continue

        # Kalit = qiymat
        m = NAQSH.match(toza)
        if not m:
            xatolar.append(Xato(i, toza, XatoTuri.NAQSH))
            continue

        kalit, qiymat = m.group(1), m.group(2)
        if not kalit:
            xatolar.append(Xato(i, toza, XatoTuri.BOSH_KALIT))
            continue
        if not qiymat.strip():
            xatolar.append(Xato(i, toza, XatoTuri.BOSH_QIYMAT))
            continue

        toliq_kalit = f"{joriy_bolim}.{kalit}" if joriy_bolim else kalit
        sozlamalar[toliq_kalit] = turni_aniqla(qiymat)

    return ParseNatijasi(sozlamalar, xatolar, bolimlar, len(qatorlar))


natija = parse(XOM)

print("=== 1. Parse natijasi ===\n")

print(f"  Muvaffaqiyat: {natija.muvaffaqiyat}")
print(f"  Qatorlar:     {natija.qatorlar_soni}")
print(f"  Sozlamalar:   {len(natija.sozlamalar)}")
print(f"  Xatolar:      {len(natija.xatolar)}")
print(f"  Bo'limlar:    {natija.bolimlar}\n")

print(f"  {'Kalit':<20} {'Qiymat':<16} {'Turi'}")
print("  " + "─" * 48)
for k, v in natija.sozlamalar.items():
    print(f"  {k:<20} {str(v):<16} {type(v).__name__}")

print(f"\n  Xatolar:")
for x in natija.xatolar:
    print(f"    {x}")


print("\n\n=== 2. ⭐ NamedTuple imkoniyatlari ===\n")

print(f"  Nom bilan:      natija.sozlamalar → {len(natija.sozlamalar)} element")
print(f"  Indeks bilan:   natija[0]         → {len(natija[0])} element")
print(f"  Ochish:         s, x, b, n = natija")
s, x, b, n = natija
print(f"                  s={len(s)}, x={len(x)}, b={len(b)}, n={n}")
print(f"  Bool:           bool(natija)      → {bool(natija)}")
print(f"  Maydonlar:      {ParseNatijasi._fields}")


print("\n\n=== 3. Turli natija shakllari ===\n")


def ol_tuple(sozlamalar, kalit):
    """tuple: (topildi, qiymat)"""
    if kalit in sozlamalar:
        return True, sozlamalar[kalit]
    return False, None


def ol_none(sozlamalar, kalit):
    """None: topilmasa None"""
    return sozlamalar.get(kalit)


_YOQ = object()


def ol_sentinel(sozlamalar, kalit, sukut=_YOQ):
    """Sentinel: None ham yaroqli qiymat"""
    if kalit in sozlamalar:
        return sozlamalar[kalit]
    if sukut is _YOQ:
        raise KeyError(kalit)
    return sukut


def ol_istisno(sozlamalar, kalit):
    """Istisno: topilmasa xato"""
    return sozlamalar[kalit]


S = {"a": 1, "b": None}

SINOVLAR = ["a", "b", "yoq"]

print(f"  S = {S}\n")
print(f"  {'Kalit':<8} {'tuple':<20} {'None':<10} {'sentinel':<14} {'istisno'}")
print("  " + "─" * 66)
for kalit in SINOVLAR:
    t = str(ol_tuple(S, kalit))
    n = repr(ol_none(S, kalit))
    try:
        se = repr(ol_sentinel(S, kalit))
    except KeyError:
        se = "KeyError"
    try:
        i = repr(ol_istisno(S, kalit))
    except KeyError:
        i = "KeyError"
    print(f"  {kalit:<8} {t:<20} {n:<10} {se:<14} {i}")

print("""
  ⭐ Qaysi birini tanlash:

     tuple    — "topildi" ni farqlash kerak, lekin uzun
     None     — eng oddiy, LEKIN None ni farqlab bo'lmaydi
     sentinel — None ham yaroqli qiymat bo'lsa ⭐
     istisno  — topilmaslik XATO bo'lsa
""")


print("\n=== 4. Validatsiya — natija turi bilan ===\n")


@dataclass
class Validatsiya:
    """Muvaffaqiyat/xato natijasi."""
    ok: bool
    qiymat: Any = None
    xatolar: list[str] = field(default_factory=list)

    @classmethod
    def muvaffaqiyat(cls, qiymat):
        return cls(True, qiymat)

    @classmethod
    def xato(cls, *xabarlar):
        return cls(False, xatolar=list(xabarlar))

    def __bool__(self):
        return self.ok

    def yoki(self, sukut):
        """Xato bo'lsa sukut qiymat."""
        return self.qiymat if self.ok else sukut


SXEMA = {
    "host": (str, lambda v: len(v) > 0),
    "port": (int, lambda v: 1 <= v <= 65535),
    "ssl": (bool, lambda v: True),
    "timeout": (float, lambda v: v > 0),
}


def tekshir(sozlamalar: dict) -> Validatsiya:
    """⭐ Erta qaytish + xatolarni to'plash."""
    xatolar = []

    for kalit, (kutilgan_tur, shart) in SXEMA.items():
        if kalit not in sozlamalar:
            xatolar.append(f"{kalit}: majburiy maydon yo'q")
            continue

        qiymat = sozlamalar[kalit]

        if not isinstance(qiymat, kutilgan_tur):
            xatolar.append(
                f"{kalit}: {kutilgan_tur.__name__} kutildi, "
                f"{type(qiymat).__name__} keldi"
            )
            continue

        if not shart(qiymat):
            xatolar.append(f"{kalit}: {qiymat!r} tekshiruvdan o'tmadi")

    if xatolar:
        return Validatsiya.xato(*xatolar)
    return Validatsiya.muvaffaqiyat(sozlamalar)


SINOVLAR = [
    ("To'g'ri", {"host": "x", "port": 5432, "ssl": True, "timeout": 30.0}),
    ("Port noto'g'ri", {"host": "x", "port": 99999, "ssl": True, "timeout": 1.0}),
    ("Tur noto'g'ri", {"host": "x", "port": "5432", "ssl": True, "timeout": 1.0}),
    ("Maydon yo'q", {"host": "x", "port": 5432}),
]

for nom, s in SINOVLAR:
    v = tekshir(s)
    belgi = "✅" if v else "❌"
    print(f"  {belgi} {nom}:")
    if v:
        print(f"      {len(v.qiymat)} maydon to'g'ri")
    else:
        for x in v.xatolar:
            print(f"      • {x}")
    print()

print(f"  Zanjirlash:")
v = tekshir({"host": "x"})
print(f"    tekshir({{'host':'x'}}).yoki('SUKUT') → {v.yoki('SUKUT')!r}")


print("\n=== 5. Generator bilan quvur ===\n")


def qatorlarni_oqi(matn: str):
    """Generator — bir vaqtda bitta qator."""
    for i, qator in enumerate(matn.strip().splitlines(), 1):
        yield i, qator.strip()


def bosh_va_izohsiz(qatorlar):
    for i, q in qatorlar:
        if not q or q.startswith("#"):
            continue
        yield i, q


def juftliklar(qatorlar):
    """⭐ Xatolarni ham beradi."""
    for i, q in qatorlar:
        m = NAQSH.match(q)
        if m and m.group(1) and m.group(2).strip():
            yield ("ok", i, m.group(1), turni_aniqla(m.group(2)))
        elif not BOLIM.match(q):
            yield ("xato", i, q, None)


quvur = juftliklar(bosh_va_izohsiz(qatorlarni_oqi(XOM)))

print(f"  qatorlarni_oqi → bosh_va_izohsiz → juftliklar\n")
print(f"  {'Holat':<8} {'Qator':>6} {'Kalit/matn':<20} {'Qiymat'}")
print("  " + "─" * 52)
for holat, i, kalit, qiymat in quvur:
    belgi = "✅" if holat == "ok" else "❌"
    print(f"  {belgi:<8} {i:>6} {str(kalit)[:18]:<20} {qiymat!r}")

print("""
  ⭐ Har bosqich generator — xotira O(1).
     Bir necha yuz megabaytlik konfiguratsiyani ham qayta ishlaydi.
""")


print("\n=== 6. Xulosa: return dizayni ===\n")

print("""
  Bu misolda ishlatilgan naqshlar:

    ParseNatijasi(NamedTuple)     4 ta qiymat — nom bilan ⭐
    Validatsiya(dataclass)        muvaffaqiyat/xato + __bool__
    ol_sentinel(d, k, sukut=_YOQ) None ham yaroqli qiymat
    continue (guard clause)        erta o'tkazib yuborish
    yield (generator quvuri)       katta ma'lumot, dangasa

  Qaror daraxti:

    1 qiymat              → qiymatning o'zi
    2-3 bog'liq qiymat    → tuple
    3+ qiymat             → NamedTuple ⭐
    Muvaffaqiyat/xato     → dataclass + __bool__, yoki istisno
    Ixtiyoriy             → T | None (yoki sentinel)
    Ko'p element          → list (kichik) yoki generator (katta) ⭐
    Yon ta'sir            → None (-> None)
""")

Natijaning muhim qismi:

text
=== 1. Parse natijasi ===

  Muvaffaqiyat: False
  Qatorlar:     13
  Sozlamalar:   5
  Xatolar:      3
  Bo'limlar:    ["bo'lim"]

  Kalit                Qiymat           Turi
  ────────────────────────────────────────────────
  host                 db.wisar.uz      str
  port                 5432             int
  ssl                  True             bool
  timeout              30.5             float
  bo'lim.ichki         qiymat           str

  Xatolar:
      8: naqsh mos kelmadi — 'notogri qator'
      9: naqsh mos kelmadi — '= qiymatsiz'
     10: qiymat bo'sh — 'kalit ='

=== 3. Turli natija shakllari ===
  Kalit    tuple                None       sentinel       istisno
  ──────────────────────────────────────────────────────────────────
  a        (True, 1)            1          1              1
  b        (True, None)         None       None           None
  yoq      (False, None)        None       KeyError       KeyError

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


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"Funksiya bir nechta qiymat qaytaradi" Bitta tuple qaytaradi
"return faqat oxirida bo'ladi" Istalgan joyda, bir nechta marta
"Bir nechta return — yomon uslub" Erta qaytish — yaxshi uslub
"finally return dan keyin bajarilmaydi" Bajariladi
"finally da return xavfsiz" Asl natijani va istisnoni bosib o'tadi
"Generatorda return qiymat qaytaradi" StopIteration.value ga o'raladi
"return break kabi" break — bitta sikl, return — butun funksiya
"return with ni chetlab o'tadi" __exit__ chaqiriladi
"else return dan keyin kerak" Kerak emas — return chiqib ketadi

6. Keng tarqalgan xatolar va yechimlari

1. return unutish

python
def f(r):
    [x * 2 for x in r]              # ❌ None
    return [x * 2 for x in r]       # ✅

2. Rekursiyada return unutish

python
def fib(n):
    if n < 2: return n
    fib(n-1) + fib(n-2)             # ❌
    return fib(n-1) + fib(n-2)      # ✅

3. Shartli qaytarish to'liq emas

python
def f(x):
    if x > 0:
        return "musbat"
    # ⚠️ x <= 0 → None
    return "musbat emas"            # ✅

4. finally da return

python
try:
    return 1
finally:
    return 2                        # ❌ ruff B012

try:
    return 1
finally:
    tozalash()                      # ✅

5. Tasodifiy vergul

python
return natija,                      # ⚠️ (natija,)
return natija                       # ✅

6. Ko'p qiymatli tuple

python
return a, b, c, d, e                # ⚠️ [3] nima?
return Natija(a, b, c, d, e)        # ✅ NamedTuple

7. Generatorda return qiymat kutish

python
def g():
    yield 1
    return 2
list(g())                           # ⚠️ [1] — 2 yo'q

8. None va istisno chalkashligi

python
def topish(r, x):
    for y in r:
        if y == x: return y
    raise ValueError("topilmadi")   # ⚠️ topilmaslik normal bo'lsa
    return None                     # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 7.1-dars (o'tilgan): return asoslari, None
  • 7.2-dars (o'tilgan): obyektga havola qaytarish
  • 6.5, 6.6-darslar (o'tilgan): tuple, NamedTuple
  • 5.2-dars (o'tilgan): guard clause uslubi
  • 9-qism: try/except/finally, istisnolar
  • 10, 14-qismlar: generatorlar, yield from, korutinlar
  • 14-dars: -> None, -> T | None, mypy

8. Eng yaxshi amaliyotlar

  1. Erta qaytish — asosiy uslub. Xato holatlarini oldinga, asosiy yo'lni oxiriga.

  2. return dan keyin else kerak emas. Kod tekisroq bo'ladi.

  3. 3+ qiymat — NamedTuple. tuple indekslari o'qilmaydi.

  4. finally da return/raise yozmang. Asl natija va istisnoni yutadi.

  5. Har yo'lda return borligini tekshiring. mypy --strict yordam beradi.

  6. -> None aniq yozing. Yon ta'sirli funksiya uchun.

  7. None — kutilgan "yo'q", istisno — xato. d.get vs d[k].

  8. Katta natija — generator. return list xotirani to'ldiradi.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
1.  def f(): return
    print(f())
2.  def f(): return 1, 2
    print(type(f()))
3.  def f(): return 1,
    print(f())
4.  def f():
        try: return 1
        finally: print("x")
    print(f())
5.  def f():
        try: return 1
        finally: return 2
    print(f())
6.  def f():
        try: raise ValueError
        finally: return "ok"
    print(f())
7.  def f():
        x = [1]
        try: return x
        finally: x.append(2)
    print(f())
8.  def g(): yield 1; return 2
    print(list(g()))
9.  def g(): yield 1; return 2
    gen = g(); next(gen)
    try: next(gen)
    except StopIteration as e: print(e.value)
10. def f():
        for i in range(3):
            return i
    print(f())
11. def f(x):
        if x > 0: return "a"
    print(f(-1))
12. def g(): return 1
    print(type(g()), type(g))
Javoblar
  1. None
  2. <class 'tuple'>
  3. (1,) — vergul tuple yaratdi
  4. x chiqadi, keyin 1
  5. 2 — finally bosib o'tdi
  6. ok — istisno yutildi
  7. [1, 2] — obyekt o'zgardi
  8. [1] — return 2 ko'rinmaydi
  9. 2 — StopIteration.value
  10. 0 — birinchi iteratsiyada chiqdi
  11. None
  12. <class 'int'> <class 'function'> — g() natija, g funksiyaning o'zi

Vazifa 2: Xatolarni tuzating

python
1.  def ikkilash(r): [x*2 for x in r]
2.  def fib(n):
        if n < 2: return n
        fib(n-1) + fib(n-2)
3.  try: return 1
    finally: return 2
4.  def f(x):
        if x > 0: return "musbat"
5.  return natija,
6.  return ism, yosh, bolim, maosh, sana, holat
7.  def g():
        yield 1
        return [1, 2]      # ro'yxat kerak
8.  def toifa(b):
        if b >= 90: return "a"
        else:
            if b >= 70: return "b"
            else: return "c"
Javoblar
python
1.  return [x*2 for x in r]
2.  return fib(n-1) + fib(n-2)
3.  finally da faqat tozalash, return emas
4.  else yo'lini ham qo'shing: return "musbat emas"
5.  return natija
6.  NamedTuple yarating
7.  yield from [1, 2]   yoki generatorni list(g()) bilan
8.  if b >= 90: return "a"
    if b >= 70: return "b"
    return "c"

Vazifa 3: Natija turlari kutubxonasi

Yozing:

  1. Natija[T] — ok/xato (Rust Result kabi)
  2. Ixtiyoriy[T] — bor/yo'q (Rust Option kabi)
  3. xarita(f), keyin(f) — zanjirlash
  4. yoki(sukut), yoki_chaqir(f) — sukut qiymat
  5. __bool__, __iter__, __repr__
  6. match/case bilan ishlashi

Vazifa 4: Guard clause refaktoringi

Berilgan funksiyalarni erta qaytishga o'tkazing:

python
def f1(a, b, c):
    if a:
        if b:
            if c:
                return a + b + c
            else: return 0
        else: return -1
    else: return -2

def f2(malumot):
    natija = None
    if malumot is not None:
        if isinstance(malumot, list):
            if len(malumot) > 0:
                natija = sum(malumot) / len(malumot)
    return natija

Va aksincha: bitta return bilan yozing, farqni solishtiring.

Vazifa 5: finally tadqiqoti

Dastur yozing:

  1. try/except/else/finally bajarilish tartibini kuzatsin
  2. Har kombinatsiya uchun (return, raise, break, continue)
  3. Natija jadval ko'rinishida
  4. finally da return/raise/break ta'sirini ko'rsatsin
  5. ruff B012 topadigan holatlarni sanab chiqsin

Vazifa 6: Generator vs ro'yxat

Vosita yozing:

  1. Bir vazifani ikki xil yozing (return list / yield)
  2. O'lchang: vaqt, xotira, birinchi natijagacha vaqt
  3. Erta to'xtash bilan va busiz
  4. Grafik chizing (█ bilan)
  5. Qaysi holatda qaysi biri yaxshiroq — tavsiya

Vazifa 7: O'ylash

Nega Python finally da return ga ruxsat beradi, garchi u istisnolarni jimgina yutsa ham?

Javob

Chunki cheklash boshqa foydali holatlarni ham taqiqlardi.

Muammo:

python
def f():
    try:
        raise ValueError("muhim xato")
    finally:
        return "ok"                 # ⚠️ istisno YO'QOLADI

f()                                 # "ok" — xato yo'q!

Bu — deyarli har doim xato. Nega taqiqlanmagan?

1. finally — oddiy blok.

Pythonda finally ichida har qanday kod bo'lishi mumkin:

python
finally:
    fayl.close()
    if shart:
        qayta_urin()
    for x in resurslar:
        x.bo'shat()

Agar return taqiqlansa, break, continue, yield ham taqiqlanishi kerak — chunki ularning ham bir xil ta'siri bor:

python
for i in range(3):
    try:
        raise ValueError
    finally:
        break                       # ⚠️ ham istisnoni yutadi

Bularning hammasini taqiqlash — finally ni maxsus blokka aylantirardi.

2. Ba'zan ataylab kerak.

python
def xavfsiz_yopish(fayl):
    try:
        fayl.close()
        return True
    finally:
        # Yopish xatosini yutish — ataylab
        return False

Yoki:

python
def tozalash_bilan():
    try:
        return asosiy_ish()
    finally:
        if xato_bor:
            return zaxira_natija()  # ataylab

Bu naqshlar kam uchraydi, lekin mavjud.

3. Statik tahlil buni topadi.

Til darajasida taqiqlash o'rniga — linter darajasida ogohlantirish:

ruff B012:      jump statements in finally block
pylint W0150:   lost-exception
flake8-bugbear: B012

Bu — Pythonning umumiy yondashuvi: "Consenting adults" (voyaga yetgan foydalanuvchilar). Til ko'p narsaga ruxsat beradi, vositalar ogohlantiradi.

Boshqa namunalar:

python
_xususiy                            # kelishuv, majburiyat emas
list = [1, 2]                       # ichki nomni yopish — mumkin
def f(r=[]): ...                    # o'zgaruvchan sukut — mumkin

4. Semantika izchil.

finally ning ta'rifi: "har doim bajariladi". Agar u return qilsa, bu — funksiyadan chiqish. Bitta funksiyadan ikki marta chiqib bo'lmaydi, shuning uchun oxirgisi g'olib.

Bu — mantiqiy va oldindan aytiladigan. Maxsus qoida kerak emas.

Boshqa tillar:

Til finally da return
Python Ruxsat (linter ogohlantiradi)
Java Ruxsat (kompilyator ogohlantiradi)
C# Taqiqlangan (kompilyatsiya xatosi)
JavaScript Ruxsat
Kotlin Ruxsat (IDE ogohlantiradi)
Go Yo'q (defer boshqacha ishlaydi)

C# yagona til bu masalada qat'iy:

csharp
finally {
    return 1;       // ❌ CS0157: Control cannot leave the body of a finally clause
}

C# jamoasi buni ataylab taqiqladi — chunki ta'siri deyarli har doim xato.

Java qiziq holat:

java
finally {
    return 1;       // ✅ ruxsat, lekin javac ogohlantiradi
}

Ogohlantirish: "finally block does not complete normally".

Go — boshqa yondashuv:

go
defer func() {
    // recover() bilan istisnoni ATAYLAB ushlash mumkin
}()

Go da defer finally ga o'xshaydi, lekin u natijani o'zgartirishi uchun maxsus sintaksis kerak (nomlangan qaytarish qiymatlari). Bu — tasodifan bo'lmaydi.

Xulosa:

Python "voyaga yetgan foydalanuvchilar" falsafasiga sodiq: agar biror narsa mantiqan mumkin bo'lsa va ba'zan foydali bo'lsa, uni taqiqlamaydi. Xavfli qo'llanishlarni linterlar topadi.

Bu — savdo: til soddaroq (maxsus qoidalar yo'q), lekin foydalanuvchi ehtiyotkorroq bo'lishi kerak. Amalda ruff yoki pylint ishlatilsa, muammo yo'q.

Amaliy qoida: finally da faqat tozalash. Natija yoki xatoni o'zgartirish kerak bo'lsa — except ishlating.

Nimani mustahkamlaydi: 2.1, 2.3, 2.4-bo'limlar.


Xulosa

Bu darsda return ni chuqur o'rgandik.

Eng muhim uch fikr:

  1. "Bir nechta qiymat" — aslida bitta tuple. return a, b tuple qaytaradi, biz uni ochamiz. 3-4 qiymatdan ko'p bo'lsa NamedTuple ishlating — t[3] nima ekanini hech kim eslamaydi.

  2. Erta qaytish — asosiy uslub. Xato holatlarini oldinga, asosiy yo'lni oxiriga. return dan keyin else kerak emas, va ichma-ichlik keskin kamayadi.

  3. finally return dan keyin bajariladi. Va agar finally da return bo'lsa — u asl natijani va istisnoni bosib o'tadi. finally da faqat tozalash yozing (ruff B012).

Keyingi darsda LEGB qoidasini — Pythonning nom qidirish tartibini o'rganamiz: lokal, yopilma, global va ichki qamrovlar.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
7.7-dars: return — chuqur — IlmHamroh