Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Semantika
- 2.2. Bir nechta qiymat — aslida tuple
- 2.3. Erta qaytish (guard clause)
- 2.4. try/finally bilan
- 2.5. return vs yield
- 2.6. None semantikasi
- 2.7. Nozik holatlar
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Semantika va bir nechta qiymat
- Misol 2 — Erta qaytish va try/finally
- Misol 3 — return vs yield
- Misol 4 — Amaliy: parser va natija turlari
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
7.7-dars: return — chuqur
7-QISM — FUNKSIYALAR · 7-dars
1. Kirish va motivatsiya
return oddiy ko'rinadi:
def kvadrat(x):
return x ** 2Lekin uning atrofida ko'p nozik savol bor:
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:
def toifa(ball):
if ball >= 90:
return "a'lo"
elif ball >= 70:
return "yaxshi"
# else kerakmi?Bu darsda:
returnsemantikasi va bajarilish oqimi- Bir nechta qiymat — aslida bitta
tuple try/finallybilan nozik o'zaro ta'sir- Erta qaytish (guard clause) uslubi
returnvsyield— generator funksiyalariNonesemantikasi va tur ko'rsatkichlari
2. Nazariya — chuqur tushuntirish
2.1. Semantika
return ikki ish qiladi:
- Funksiyani darhol to'xtatadi
- Qiymatni chaqiruvchiga qaytaradi
def f():
print("bir")
return 1
print("ikki") # ❌ bajarilmaydiUch shakl:
def a(): return # None
def b(): return None # None
def c(): pass # None (return yo'q)Bytecode darajasida ham bir xil:
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:
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
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:
return 1, 2 # ✅
return (1, 2) # ✅ bir xilBitta element:
return 1, # ⚠️ (1,) — tuple!
return (1,) # ⚠️ bir xil
return 1 # ✅ intTasodifiy vergul — jimgina xato manbai (6.5-dars).
Qachon nomli natija:
3-4 qiymatdan ko'p bo'lsa, tuple chalkash bo'ladi:
def tahlil(matn):
return len(matn), len(matn.split()), matn.count("."), ...
# ⚠️ [3] nima edi?Yaxshiroq — NamedTuple (6.6-dars):
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 hamYoki dataclass:
@dataclass
class Natija:
muvaffaqiyat: bool
qiymat: Any = None
xato: str | None = None dict qaytarish — kam tavsiya:
def f():
return {"a": 1, "b": 2} # ⚠️ kalitlar tekshirilmaydiIDE yordam bermaydi, xato yozilgan kalit ish vaqtida chiqadi.
2.3. Erta qaytish (guard clause)
Ichma-ich if:
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 NoneErta qaytish:
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:
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 emasreturn chiqib ketgani uchun keyingi if faqat oldingisi bajarilmaganda tekshiriladi.
Lekin elif ba'zan aniqroq:
# Mantiqiy bog'liqlikni ko'rsatadi
if a:
return 1
elif b: # "a bo'lmasa VA b bo'lsa"
return 2Bu — uslub masalasi. ruff/pylint no-else-return qoidasi else ni olib tashlashni taklif qiladi.
Xato holatlarini oldinga:
def bol(a, b):
if b == 0:
raise ValueError("nolga bo'lish") # ✅ oldinda
return a / b2.4. try/finally bilan
finally DOIM bajariladi — hatto return dan keyin ham:
def f():
try:
return 1
finally:
print("finally") # ✅ bajariladi
f() # "finally" chiqadi, keyin 1 qaytadiTartib:
return 1— qaytariladigan qiymat hisoblanadi va saqlanadifinallybajariladi- Saqlangan qiymat qaytariladi
finally da return — asl qiymatni BOSIB O'TADI:
def f():
try:
return 1
finally:
return 2 # ⚠️
f() # 2Istisnoni ham yutadi:
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:
def f():
x = [1]
try:
return x # x obyektiga havola saqlanadi
finally:
x.append(2) # ⚠️ o'sha obyekt o'zgaradi
f() # [1, 2]def g():
x = 1
try:
return x # qiymat (1) saqlanadi
finally:
x = 99 # ✅ yangi obyekt — ta'sir qilmaydi
g() # 1Bu — 7.2-darsdagi yorliq/obyekt farqi.
try/except bilan:
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:
def oddiy():
return 1
def generator():
yield 1
type(oddiy()) # <class 'int'>
type(generator()) # <class 'generator'> yield bo'lsa, return — boshqacha ishlaydi:
def g():
yield 1
yield 2
return 3 # ⚠️ qiymat StopIteration ga o'raladi
gen = g()
next(gen) # 1
next(gen) # 2
next(gen) # ❌ StopIteration: 3return qiymati iteratsiyada ko'rinmaydi:
list(g()) # [1, 2] — 3 yo'qUni olish uchun:
gen = g()
try:
while True:
next(gen)
except StopIteration as x:
natija = x.value # 3Yoki yield from:
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:
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:
# 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 qaytadiTur ko'rsatkichlari farqni ko'rsatadi:
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:
def f() -> int:
if shart:
return 1
# mypy: Missing return statement None yoki istisno?
# 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] # IndexErrorQoida: agar "natija yo'q" kutilgan bo'lsa — None. Agar bu xato bo'lsa — istisno.
Sentinel (7.3-dars) — None ham yaroqli qiymat bo'lsa:
_YOQ = object()
def ol(d, kalit, sukut=_YOQ):
if kalit in d:
return d[kalit]
if sukut is _YOQ:
raise KeyError(kalit)
return sukut2.7. Nozik holatlar
1. return sikl ichida — sikl to'xtaydi:
def birinchi_juft(r):
for x in r:
if x % 2 == 0:
return x # ✅ butun funksiyadan chiqadi
return Nonebreak faqat siklni to'xtatadi, return — funksiyani.
2. return with ichida — __exit__ chaqiriladi:
def f(yol):
with open(yol) as fayl:
return fayl.read() # ✅ fayl yopiladi3. Rekursiyada return unutish:
def fib(n):
if n < 2:
return n
fib(n - 1) + fib(n - 2) # ❌ return yo'q → None4. Shartli qaytarish to'liq emas:
def f(x):
if x > 0:
return "musbat"
# ⚠️ x <= 0 bo'lsa Nonemypy --strict buni topadi.
5. return ifodada:
return x if shart else y # ✅
return [f(i) for i in r] # ✅
return (yield) # ⚠️ generator — kam ishlatiladi6. Bir nechta return — muammomi?
Eski "structured programming" qoidasi: "bir kirish, bir chiqish".
Zamonaviy Pythonda — yo'q. Erta qaytish o'qilishni yaxshilaydi. Muhimi:
- Har
returnaniq bo'lsin - Funksiya qisqa bo'lsin
- Tozalash
with/finallybilan bo'lsin
3. Tez ma'lumotnoma
Semantika
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 chiqadiBir nechta qiymat
def f(): return min(r), max(r) tuple
a, b = f() ochish
3-4 dan ko'p → NamedTuple yoki dataclassErta qaytish (guard clause)
def f(x):
if xato_holat: return None ✅ oldinga
if boshqa_xato: return None
return asosiy_natija ✅ oxirida
else/elif KERAK EMAS — return chiqib ketaditry/finally
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
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'xtatadiNone semantikasi
-> 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
"""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:
=== 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 ← ravshanNima ko'rsatdi: 2.1, 2.2-bo'limlar.
Misol 2 — Erta qaytish va try/finally
"""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:
=== 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. finallyNima ko'rsatdi: 2.3, 2.4-bo'limlar.
Misol 3 — return vs yield
"""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:
=== 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,000xNima ko'rsatdi: 2.5-bo'lim.
Misol 4 — Amaliy: parser va natija turlari
"""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:
=== 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 KeyErrorNima 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
def f(r):
[x * 2 for x in r] # ❌ None
return [x * 2 for x in r] # ✅2. Rekursiyada return unutish
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
def f(x):
if x > 0:
return "musbat"
# ⚠️ x <= 0 → None
return "musbat emas" # ✅4. finally da return
try:
return 1
finally:
return 2 # ❌ ruff B012
try:
return 1
finally:
tozalash() # ✅5. Tasodifiy vergul
return natija, # ⚠️ (natija,)
return natija # ✅6. Ko'p qiymatli tuple
return a, b, c, d, e # ⚠️ [3] nima?
return Natija(a, b, c, d, e) # ✅ NamedTuple7. Generatorda return qiymat kutish
def g():
yield 1
return 2
list(g()) # ⚠️ [1] — 2 yo'q8. None va istisno chalkashligi
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):
returnasoslari,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
Erta qaytish — asosiy uslub. Xato holatlarini oldinga, asosiy yo'lni oxiriga.
returndan keyinelsekerak emas. Kod tekisroq bo'ladi.3+ qiymat —
NamedTuple.tupleindekslari o'qilmaydi.finallydareturn/raiseyozmang. Asl natija va istisnoni yutadi.Har yo'lda
returnborligini tekshiring.mypy --strictyordam beradi.-> Noneaniq yozing. Yon ta'sirli funksiya uchun.None— kutilgan "yo'q", istisno — xato.d.getvsd[k].Katta natija — generator.
return listxotirani to'ldiradi.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
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
None<class 'tuple'>(1,)— vergul tuple yaratdixchiqadi, keyin12—finallybosib o'tdiok— istisno yutildi[1, 2]— obyekt o'zgardi[1]—return 2ko'rinmaydi2—StopIteration.value0— birinchi iteratsiyada chiqdiNone<class 'int'> <class 'function'>—g()natija,gfunksiyaning o'zi
Vazifa 2: Xatolarni tuzating
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
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:
Natija[T]—ok/xato(RustResultkabi)Ixtiyoriy[T]—bor/yo'q(RustOptionkabi)xarita(f),keyin(f)— zanjirlashyoki(sukut),yoki_chaqir(f)— sukut qiymat__bool__,__iter__,__repr__match/casebilan ishlashi
Vazifa 4: Guard clause refaktoringi
Berilgan funksiyalarni erta qaytishga o'tkazing:
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 natijaVa aksincha: bitta return bilan yozing, farqni solishtiring.
Vazifa 5: finally tadqiqoti
Dastur yozing:
try/except/else/finallybajarilish tartibini kuzatsin- Har kombinatsiya uchun (
return,raise,break,continue) - Natija jadval ko'rinishida
finallydareturn/raise/breakta'sirini ko'rsatsinruffB012 topadigan holatlarni sanab chiqsin
Vazifa 6: Generator vs ro'yxat
Vosita yozing:
- Bir vazifani ikki xil yozing (
return list/yield) - O'lchang: vaqt, xotira, birinchi natijagacha vaqt
- Erta to'xtash bilan va busiz
- Grafik chizing (
█bilan) - 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:
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:
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:
for i in range(3):
try:
raise ValueError
finally:
break # ⚠️ ham istisnoni yutadiBularning hammasini taqiqlash — finally ni maxsus blokka aylantirardi.
2. Ba'zan ataylab kerak.
def xavfsiz_yopish(fayl):
try:
fayl.close()
return True
finally:
# Yopish xatosini yutish — ataylab
return FalseYoki:
def tozalash_bilan():
try:
return asosiy_ish()
finally:
if xato_bor:
return zaxira_natija() # ataylabBu 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: B012Bu — Pythonning umumiy yondashuvi: "Consenting adults" (voyaga yetgan foydalanuvchilar). Til ko'p narsaga ruxsat beradi, vositalar ogohlantiradi.
Boshqa namunalar:
_xususiy # kelishuv, majburiyat emas
list = [1, 2] # ichki nomni yopish — mumkin
def f(r=[]): ... # o'zgaruvchan sukut — mumkin4. 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:
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:
finally {
return 1; // ✅ ruxsat, lekin javac ogohlantiradi
}Ogohlantirish: "finally block does not complete normally".
Go — boshqa yondashuv:
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:
"Bir nechta qiymat" — aslida bitta
tuple.return a, btuple qaytaradi, biz uni ochamiz. 3-4 qiymatdan ko'p bo'lsaNamedTupleishlating —t[3]nima ekanini hech kim eslamaydi.Erta qaytish — asosiy uslub. Xato holatlarini oldinga, asosiy yo'lni oxiriga.
returndan keyinelsekerak emas, va ichma-ichlik keskin kamayadi.finallyreturndan keyin bajariladi. Va agarfinallydareturnbo'lsa — u asl natijani va istisnoni bosib o'tadi.finallyda faqat tozalash yozing (ruffB012).
Keyingi darsda LEGB qoidasini — Pythonning nom qidirish tartibini o'rganamiz: lokal, yopilma, global va ichki qamrovlar.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!