Mundarija (23)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Ikki tushuncha
- 2.2. Protokol: __iter__ va __next__
- 2.3. for sikli aslida nima qiladi
- 2.4. Iterator bir martalik
- 2.5. next() ning sukut qiymati
- 2.6. iter(funksiya, belgi) — ikki argumentli shakl
- 2.7. Dangasa hisoblash
- 2.8. Iteratsiya paytida o'zgartirish
- 2.9. collections.abc bilan tekshirish
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Protokolni ichidan ko'rish
- Misol 2 — Bir martalik iteratorning tuzoqlari
- Misol 3 — iter(funksiya, belgi) va bo'laklab o'qish
- Misol 4 — Amaliy: dangasa ma'lumot quvuri
- 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
10.1-dars: Iterator va iterable
10-QISM — ILG'OR TIL IMKONIYATLARI · 1-dars
1. Kirish va motivatsiya
Bu kod nima chiqaradi?
sonlar = map(int, ["1", "2", "3"])
print(sum(sonlar))
print(sum(sonlar))Ko'pchilik 6 va 6 deb javob beradi. Aslida:
6
0Ikkinchi sum bo'sh narsani qo'shdi. sonlar ro'yxat emas edi — u iterator, va iterator faqat bir marta aylanadi.
Endi bunisi:
royxat = [1, 2, 3]
print(sum(royxat))
print(sum(royxat))6
6Ro'yxat — iterable. Undan istalgancha marta yangi iterator olish mumkin.
Bu farqni tushunmaslik real loyihalarda juda sirli xatolarga olib keladi:
- Fayldan o'qilgan qatorlar ikkinchi marta "yo'qolib qoladi"
zipbilan juftlangan ma'lumotning yarmi "g'oyib" bo'ladiif x in generator:tekshiruvidan keyin sikl elementlarni o'tkazib yuboradi- Funksiya bir marta to'g'ri, ikkinchi marta bo'sh natija qaytaradi
Bu darsda:
- Iterable va iterator — ikki xil tushuncha
forsikli aslida qanday ishlaydiiter()vanext()— protokolning ikki funksiyasi- Iteratorning tugashi va bir martalik tabiati
iter(funksiya, belgi)— kam ma'lum ikki argumentli shakl- Dangasa hisoblash va xotira
- Keng tarqalgan tuzoqlar
Keyingi darsda 10.2-bob o'z iterator sinflaringizni yozasiz. Bu darsda esa protokolni ishlatish va ichidan tushunishni o'rganamiz.
2. Nazariya — chuqur tushuntirish
2.1. Ikki tushuncha
Iterable — "aylanib chiqsa bo'ladigan" obyekt. U iter() ga berilganda iterator qaytaradi.
Iterator — "hozir qayerda turganini biladigan" obyekt. U next() ga berilganda keyingi elementni qaytaradi, elementlar tugasa StopIteration ko'taradi.
royxat = [10, 20, 30] # iterable
it = iter(royxat) # iterator
next(it) # 10
next(it) # 20
next(it) # 30
next(it) # ❌ StopIterationO'xshatish:
| Kitob (iterable) | Xatcho'p (iterator) | |
|---|---|---|
| Nima | Mazmun | Joriy sahifa |
| Nechta | Bitta | Istalgancha |
| Holati | O'zgarmaydi | Oldinga siljiydi |
| Qayta o'qish | Yangi xatcho'p qo'ying | Orqaga qaytmaydi |
Bitta kitobga bir nechta xatcho'p qo'yish mumkin — har biri o'z sahifasida turadi. Xuddi shunday, bitta ro'yxatdan bir nechta mustaqil iterator olish mumkin.
2.2. Protokol: __iter__ va __next__
Python bu tushunchalarni ikki "dunder" metod orqali aniqlaydi:
| Tushuncha | Qaysi metod kerak | Chaqiruvchi |
|---|---|---|
| Iterable | __iter__() → iterator qaytaradi |
iter(obj) |
| Iterator | __next__() → keyingi element |
next(it) |
| Iterator | __iter__() → o'zini qaytaradi |
iter(it) |
Muhim qoida: har bir iterator ham iterable. Uning __iter__ metodi self ni qaytaradi. Shuning uchun iteratorni ham for ga berish mumkin:
it = iter([1, 2, 3])
iter(it) is it # True — iterator o'zini qaytaradiLekin teskarisi to'g'ri emas: ro'yxat iterable, ammo iterator emas:
royxat = [1, 2, 3]
iter(royxat) is royxat # False — har safar YANGI iterator
next(royxat) # ❌ TypeError: 'list' object is not an iterator2.3. for sikli aslida nima qiladi
Bu kod:
for x in royxat:
print(x)Python uchun taxminan quyidagicha:
_it = iter(royxat) # 1. iterator olish
while True:
try:
x = next(_it) # 2. keyingi element
except StopIteration: # 3. tugadi — sikldan chiqish
break
print(x) # 4. sikl tanasiShundan uchta muhim xulosa:
forhar safar boshidaiter()ni bir marta chaqiradi- Elementlar
next()bilan birma-bir olinadi — hammasi oldindan xotiraga yuklanmaydi StopIteration— xato emas, "tugadi" signali
Xuddi shu protokolni ishlatadigan boshqa joylar:
list(x) tuple(x) set(x) dict(x) # konstruktorlar
sum(x) min(x) max(x) sorted(x) # yig'uvchilar
a, b, c = x # ochish
[*x] {*x} f(*x) # yulduzcha
x in y # (y da __contains__ bo'lmasa)
zip(x, y) map(f, x) enumerate(x) # moslashtiruvchilar2.4. Iterator bir martalik
Iterator faqat oldinga yuradi va qaytmaydi:
it = iter([1, 2, 3])
list(it) # [1, 2, 3]
list(it) # [] ⚠️ tugaganQaysi obyektlar iterator (bir martalik) va qaysilari iterable (qayta ishlatiladigan):
| Qayta aylanadi (iterable) | Bir martalik (iterator) |
|---|---|
list, tuple, str |
iter(...) natijasi |
dict, set, frozenset |
map(...), filter(...), zip(...) |
range(...) |
enumerate(...), reversed(...) |
dict.keys(), .values(), .items() |
generator ifodasi (x for x in ...) |
fayl obyekti open(...) |
|
itertools funksiyalari natijasi |
range va dict.keys() ko'pincha iterator deb o'ylanadi, lekin ular qayta ishlatiladigan iterable:
r = range(3)
list(r), list(r) # ([0, 1, 2], [0, 1, 2]) ✅Qanday tekshirish:
iter(x) is x # True → iterator (bir martalik)
# False → iterable konteyner2.5. next() ning sukut qiymati
next() ikkinchi argument oladi — tugaganda StopIteration o'rniga shu qaytadi:
it = iter([])
next(it, None) # None — xato yo'q
next(it, "tugadi") # 'tugadi'Bu "birinchi mos elementni topish"da juda qulay:
birinchi_juft = next((x for x in sonlar if x % 2 == 0), None)2.6. iter(funksiya, belgi) — ikki argumentli shakl
iter() ning kam ma'lum shakli: funksiyani belgi qiymat qaytarguncha qayta-qayta chaqiradi.
iter(chaqiriluvchi, belgi)import random
zarlar = iter(lambda: random.randint(1, 6), 6)
list(zarlar) # 6 chiqquncha tashlanganlar, masalan [3, 1, 4]Klassik qo'llanilishi — faylni bo'laklab o'qish:
with open("katta.bin", "rb") as f:
for bolak in iter(lambda: f.read(4096), b""):
ishla(bolak) # b"" — fayl oxiri belgisiwhile True + if not bolak: break o'rniga bitta toza qator.
2.7. Dangasa hisoblash
Iterator elementni so'ralganda hisoblaydi. Bu ikki katta foyda beradi:
1. Xotira:
sum([x * x for x in range(10_000_000)]) # ⚠️ 10M elementli ro'yxat yaratiladi
sum(x * x for x in range(10_000_000)) # ✅ bir vaqtda bitta element2. Erta to'xtash:
katta = map(qimmat_hisob, range(1_000_000))
next(x for x in katta if x > 100) # birinchisi topilishi bilan to'xtaydiLekin dangasalikning narxi bor: xato ham kechikadi.
natijalar = map(int, ["1", "2", "uch"]) # ❌ hali xato YO'Q
print("tayyor") # bajariladi
list(natijalar) # ❌ ValueError — faqat shu yerda2.8. Iteratsiya paytida o'zgartirish
d = {"a": 1, "b": 2}
for k in d:
d["c"] = 3 # ❌ RuntimeError: dictionary changed size during iterationset da ham xuddi shunday. Ro'yxatda esa xato chiqmaydi, lekin elementlar o'tkazib yuboriladi (5.7-dars):
r = [1, 2, 2, 3]
for x in r:
if x == 2:
r.remove(x) # ⚠️ ikkinchi 2 o'tkazib yuboriladi
# r == [1, 2, 3]Yechim — nusxa ustida aylanish yoki yangi to'plam yasash:
for k in list(d): ... # kalitlar nusxasi
r = [x for x in r if x != 2] # yangi ro'yxat2.9. collections.abc bilan tekshirish
from collections.abc import Iterable, Iterator
isinstance([1, 2], Iterable) # True
isinstance([1, 2], Iterator) # False
isinstance(iter([1, 2]), Iterator) # True isinstance(x, Iterable) faqat __iter__ borligini tekshiradi. Faqat eski __getitem__ protokoli bilan ishlaydigan obyektlarni u ko'rmaydi (8.14-dars). Eng ishonchli tekshiruv — urinib ko'rish:
try:
iter(x)
except TypeError:
print("aylanib bo'lmaydi")3. Tez ma'lumotnoma
Tushunchalar
Iterable __iter__() → iterator list, dict, str, range, set
Iterator __next__() → element map, zip, filter, generator, fayl
__iter__() → self (iterator ham iterable)Asosiy funksiyalar
iter(x) iterator olish (TypeError — aylanmaydi)
next(it) keyingi element (StopIteration — tugadi)
next(it, sukut) tugasa sukut qaytaradi
iter(f, belgi) f() belgi bermaguncha chaqiradi
iter(x) is x True → bir martalik iteratorfor ning ichki ishi
_it = iter(x)
while True:
try: el = next(_it)
except StopIteration: break
...Tuzoqlar
Iteratorni ikki marta aylanish ikkinchisi bo'sh
x in iterator elementlarni iste'mol qiladi
zip(it, it) bitta iteratordan ikki marta oladi
dict/set ni aylanishda o'zgartirish RuntimeError
map/filter dagi xato faqat iste'mol qilinganda chiqadi4. Batafsil misollar
Misol 1 — Protokolni ichidan ko'rish
"""Iterable va iterator protokolini qadamma-qadam kuzatish."""
from collections.abc import Iterable, Iterator
print("=== 1. iter() va next() qo'lda ===")
royxat = ["olma", "anor", "behi"]
it = iter(royxat)
print(f" royxat turi: {type(royxat).__name__}")
print(f" iterator turi: {type(it).__name__}")
print(f" next(it) → {next(it)!r}")
print(f" next(it) → {next(it)!r}")
print(f" next(it) → {next(it)!r}")
try:
next(it)
except StopIteration:
print(" next(it) → ❌ StopIteration (elementlar tugadi)")
print("\n=== 2. Iterator o'zini qaytaradi, konteyner — yo'q ===")
it = iter(royxat)
print(f" iter(it) is it → {iter(it) is it}")
print(f" iter(royxat) is royxat → {iter(royxat) is royxat}")
print(f" iter(royxat) is iter(royxat) → {iter(royxat) is iter(royxat)}")
try:
next(royxat)
except TypeError as e:
print(f" next(royxat) → ❌ TypeError: {e}")
print("\n=== 3. Qaysi obyekt bir martalik? ===")
NAMUNALAR = [
("list", [1, 2, 3]),
("tuple", (1, 2, 3)),
("str", "abc"),
("dict", {"a": 1}),
("dict.items()", {"a": 1}.items()),
("set", {1, 2}),
("range(3)", range(3)),
("map(...)", map(str, [1, 2])),
("filter(...)", filter(None, [0, 1])),
("zip(...)", zip("ab", "cd")),
("enumerate(...)", enumerate("ab")),
("reversed(...)", reversed([1, 2])),
("(x for x in ...)", (x for x in [1, 2])),
]
print(f" {'Obyekt':<20} {'Iterable':<10} {'Iterator':<10} {'Ikkinchi list()'}")
print(" " + "─" * 62)
for nom, obj in NAMUNALAR:
birinchi = list(obj)
ikkinchi = list(obj)
holat = "✅ bir xil" if birinchi == ikkinchi else f"⚠️ {ikkinchi}"
print(f" {nom:<20} {str(isinstance(obj, Iterable)):<10} "
f"{str(isinstance(obj, Iterator)):<10} {holat}")
print("\n=== 4. for sikli qo'lda ===")
def mening_for(iterable, tana):
"""for x in iterable: tana(x) — ning while bilan yozilgani."""
_it = iter(iterable)
qadam = 0
while True:
try:
x = next(_it)
except StopIteration:
print(f" StopIteration → {qadam} qadamdan keyin to'xtadi")
break
qadam += 1
tana(x)
mening_for("Hi!", lambda harf: print(f" element: {harf!r}"))
print("\n=== 5. Mustaqil iteratorlar ===")
harflar = "abcd"
it1 = iter(harflar)
it2 = iter(harflar)
print(f" next(it1), next(it1) → {next(it1)!r}, {next(it1)!r}")
print(f" next(it2) → {next(it2)!r} ⭐ it2 boshidan boshladi")
print(f" next(it1) → {next(it1)!r} ⭐ it1 o'z joyidan davom etdi")
print("\n=== 6. next() ning sukut qiymati ===")
sonlar = [3, 7, 9, 12, 15]
birinchi_juft = next((x for x in sonlar if x % 2 == 0), None)
birinchi_manfiy = next((x for x in sonlar if x < 0), None)
print(f" birinchi juft: {birinchi_juft}")
print(f" birinchi manfiy: {birinchi_manfiy} (topilmadi — xato yo'q)")Natijaning muhim qismi:
=== 1. iter() va next() qo'lda ===
royxat turi: list
iterator turi: list_iterator
next(it) → 'olma'
next(it) → 'anor'
next(it) → 'behi'
next(it) → ❌ StopIteration (elementlar tugadi)
=== 2. Iterator o'zini qaytaradi, konteyner — yo'q ===
iter(it) is it → True
iter(royxat) is royxat → False
iter(royxat) is iter(royxat) → False
next(royxat) → ❌ TypeError: 'list' object is not an iterator
=== 3. Qaysi obyekt bir martalik? ===
Obyekt Iterable Iterator Ikkinchi list()
──────────────────────────────────────────────────────────────
list True False ✅ bir xil
tuple True False ✅ bir xil
str True False ✅ bir xil
dict True False ✅ bir xil
dict.items() True False ✅ bir xil
set True False ✅ bir xil
range(3) True False ✅ bir xil
map(...) True True ⚠️ []
filter(...) True True ⚠️ []
zip(...) True True ⚠️ []
enumerate(...) True True ⚠️ []
reversed(...) True True ⚠️ []
(x for x in ...) True True ⚠️ []
=== 4. for sikli qo'lda ===
element: 'H'
element: 'i'
element: '!'
StopIteration → 3 qadamdan keyin to'xtadi
=== 5. Mustaqil iteratorlar ===
next(it1), next(it1) → 'a', 'b'
next(it2) → 'a' ⭐ it2 boshidan boshladi
next(it1) → 'c' ⭐ it1 o'z joyidan davom etdi
=== 6. next() ning sukut qiymati ===
birinchi juft: 12
birinchi manfiy: None (topilmadi — xato yo'q)Nima ko'rsatdi: 2.1, 2.2, 2.3, 2.4, 2.5-bo'limlar.
Misol 2 — Bir martalik iteratorning tuzoqlari
"""Iterator tugashi bilan bog'liq real xatolar."""
import io
print("=== 1. map natijasini ikki marta ishlatish ===")
narxlar_matn = ["12000", "8500", "30000"]
narxlar = map(int, narxlar_matn)
print(f" jami: {sum(narxlar)}")
bosh = "— bo'sh!"
print(f" eng katta: {max(narxlar, default=bosh)}")
narxlar = list(map(int, narxlar_matn)) # ✅ bir marta ro'yxatga
print(f" ✅ ro'yxat bilan: jami={sum(narxlar)}, eng katta={max(narxlar)}")
print("\n=== 2. `in` iteratorni iste'mol qiladi ===")
kodlar = iter(["A1", "B2", "C3", "D4"])
print(f" 'B2' in kodlar → {'B2' in kodlar}")
print(f" qolganlari: {list(kodlar)} ⚠️ A1 va B2 yo'qoldi")
print("\n=== 3. Fayl obyekti ham bir martalik ===")
fayl = io.StringIO("birinchi\nikkinchi\nuchinchi\n")
print(f" qatorlar soni: {sum(1 for _ in fayl)}")
print(f" qatorlar: {list(fayl)} ⚠️ kursor oxirida")
fayl.seek(0)
print(f" seek(0) dan keyin: {[q.strip() for q in fayl]}")
print("\n=== 4. zip bilan bitta iteratorni ikki marta berish ===")
qiymatlar = [1, 2, 3, 4, 5, 6]
it = iter(qiymatlar)
print(f" zip(it, it) → {list(zip(it, it))} ⭐ juftlab olish usuli")
print(f" zip(r, r) → {list(zip(qiymatlar, qiymatlar))} (ro'yxat — har safar yangi)")
print("\n=== 5. Funksiya iteratorni 'yeb qo'yadi' ===")
def tekshir_va_hisobla(elementlar):
"""Bo'sh emasligini tekshiradi, keyin sanaydi."""
if not any(True for _ in elementlar):
return "bo'sh"
return f"{sum(1 for _ in elementlar)} ta element"
print(f" ro'yxat bilan: {tekshir_va_hisobla([10, 20, 30])}")
print(f" iterator bilan: {tekshir_va_hisobla(iter([10, 20, 30]))} ⚠️")
print("\n=== 6. Himoya: iteratorni ro'yxatga aylantirish ===")
def xavfsiz_hisobla(elementlar):
"""Iterator kelsa ham to'g'ri ishlaydi."""
if iter(elementlar) is elementlar: # bir martalik iterator
elementlar = list(elementlar)
if not elementlar:
return "bo'sh"
return f"{len(elementlar)} ta element"
print(f" ro'yxat bilan: {xavfsiz_hisobla([10, 20, 30])}")
print(f" iterator bilan: {xavfsiz_hisobla(iter([10, 20, 30]))} ✅")
print(f" generator bilan: {xavfsiz_hisobla(x for x in range(4))} ✅")
print("\n=== 7. Kechiktirilgan xato ===")
satrlar = ["10", "20", "o'ttiz", "40"]
sonlar = map(int, satrlar)
print(" map yaratildi — hali xato yo'q")
try:
for s in sonlar:
print(f" o'qildi: {s}")
except ValueError as e:
print(f" ❌ xato faqat iste'molda: {e}")Natijaning muhim qismi:
=== 1. map natijasini ikki marta ishlatish ===
jami: 50500
eng katta: — bo'sh!
✅ ro'yxat bilan: jami=50500, eng katta=30000
=== 2. `in` iteratorni iste'mol qiladi ===
'B2' in kodlar → True
qolganlari: ['C3', 'D4'] ⚠️ A1 va B2 yo'qoldi
=== 3. Fayl obyekti ham bir martalik ===
qatorlar soni: 3
qatorlar: [] ⚠️ kursor oxirida
seek(0) dan keyin: ['birinchi', 'ikkinchi', 'uchinchi']
=== 4. zip bilan bitta iteratorni ikki marta berish ===
zip(it, it) → [(1, 2), (3, 4), (5, 6)] ⭐ juftlab olish usuli
zip(r, r) → [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)] (ro'yxat — har safar yangi)
=== 5. Funksiya iteratorni 'yeb qo'yadi' ===
ro'yxat bilan: 3 ta element
iterator bilan: 2 ta element ⚠️
=== 6. Himoya: iteratorni ro'yxatga aylantirish ===
ro'yxat bilan: 3 ta element
iterator bilan: 3 ta element ✅
generator bilan: 4 ta element ✅
=== 7. Kechiktirilgan xato ===
map yaratildi — hali xato yo'q
o'qildi: 10
o'qildi: 20
❌ xato faqat iste'molda: invalid literal for int() with base 10: "o'ttiz"Nima ko'rsatdi: 2.4, 2.7-bo'limlar va 3-bo'limdagi tuzoqlar.
Misol 3 — iter(funksiya, belgi) va bo'laklab o'qish
"""Ikki argumentli iter() ning amaliy qo'llanilishi."""
import io
import random
print("=== 1. Zar 6 chiqquncha ===")
random.seed(3)
tashlashlar = list(iter(lambda: random.randint(1, 6), 6))
print(f" 6 dan oldingi tashlashlar: {tashlashlar}")
print(f" urinishlar soni (6 bilan): {len(tashlashlar) + 1}")
print("\n=== 2. Faylni bo'laklab o'qish ===")
malumot = io.BytesIO(bytes(range(256)) * 40) # 10 240 bayt
BOLAK = 4096
hajmlar = [len(b) for b in iter(lambda: malumot.read(BOLAK), b"")]
print(f" bo'lak hajmlari: {hajmlar}")
print(f" jami: {sum(hajmlar):,} bayt")
print("\n=== 3. while bilan solishtirish ===")
malumot.seek(0)
hajmlar_while = []
while True:
bolak = malumot.read(BOLAK)
if not bolak:
break
hajmlar_while.append(len(bolak))
print(f" while natijasi: {hajmlar_while}")
print(f" bir xilmi: {hajmlar == hajmlar_while}")
print("\n=== 4. Navbatdan 'STOP' kelguncha o'qish ===")
buyruqlar = iter(["start", "yukla", "saqla", "STOP", "keyingisi"])
bajarilgan = list(iter(lambda: next(buyruqlar), "STOP"))
print(f" bajarilgan buyruqlar: {bajarilgan}")
print(f" STOP dan keyin qolgan: {list(buyruqlar)}")
print("\n=== 5. ⚠️ Belgi == bilan solishtiriladi ===")
sanoq = iter([1, 2, 3, 1.0, 5])
natija = list(iter(lambda: next(sanoq), 1.0))
print(f" belgi 1.0, oqim [1, 2, ...]: {natija} ⚠️ 1 == 1.0 → darhol to'xtadi")
print("\n=== 6. ⚠️ Birinchi argument chaqiriluvchi bo'lishi shart ===")
try:
iter([1, 2, 3], 3)
except TypeError as e:
print(f" iter([1, 2, 3], 3) → ❌ TypeError: {e}")Natijaning muhim qismi:
=== 1. Zar 6 chiqquncha ===
6 dan oldingi tashlashlar: [2, 5, 5, 2, 3, 5, 4]
urinishlar soni (6 bilan): 8
=== 2. Faylni bo'laklab o'qish ===
bo'lak hajmlari: [4096, 4096, 2048]
jami: 10,240 bayt
=== 3. while bilan solishtirish ===
while natijasi: [4096, 4096, 2048]
bir xilmi: True
=== 4. Navbatdan 'STOP' kelguncha o'qish ===
bajarilgan buyruqlar: ['start', 'yukla', 'saqla']
STOP dan keyin qolgan: ['keyingisi']
=== 5. ⚠️ Belgi == bilan solishtiriladi ===
belgi 1.0, oqim [1, 2, ...]: [] ⚠️ 1 == 1.0 → darhol to'xtadi
=== 6. ⚠️ Birinchi argument chaqiriluvchi bo'lishi shart ===
iter([1, 2, 3], 3) → ❌ TypeError: iter(v, w): v must be callableNima ko'rsatdi: 2.5, 2.6-bo'limlar.
Misol 4 — Amaliy: dangasa ma'lumot quvuri
"""Katta log faylini iteratorlar bilan qayta ishlash — xotira va erta to'xtash."""
import io
import itertools
import tracemalloc
# ── Sun'iy log: 200 000 qator ──
DARAJALAR = ["INFO", "INFO", "INFO", "WARN", "ERROR"]
qatorlar = []
for i in range(200_000):
daraja = DARAJALAR[i % len(DARAJALAR)]
qatorlar.append(f"2026-09-14 12:{i % 60:02d}:00 {daraja} so'rov #{i} {i % 97} ms\n")
LOG = "".join(qatorlar)
del qatorlar
def log_ochish():
return io.StringIO(LOG)
def xatolar_royxat(fayl):
"""❌ Hammasini xotiraga yuklaydi."""
qatorlar = fayl.readlines()
xatolar = [q for q in qatorlar if " ERROR " in q]
return [int(q.split()[-2]) for q in xatolar]
def xatolar_iterator(fayl):
"""✅ Qatorma-qator, hech narsa to'planmaydi."""
xato_qatorlar = (q for q in fayl if " ERROR " in q)
return (int(q.split()[-2]) for q in xato_qatorlar)
def olcha(nom, funksiya):
fayl = log_ochish() # fayl o'lchovdan TASHQARIDA ochiladi
tracemalloc.start()
natija = funksiya(fayl)
_, tepa = tracemalloc.get_traced_memory()
tracemalloc.stop()
print(f" {nom:<26} natija={natija:<11,} xotira cho'qqisi={tepa / 1024:>8,.0f} KB")
print("=== 1. Xotira: ro'yxat vs iterator ===")
olcha("ro'yxatlar bilan (sum)", lambda f: sum(xatolar_royxat(f)))
olcha("iteratorlar bilan (sum)", lambda f: sum(xatolar_iterator(f)))
print("\n=== 2. Erta to'xtash: birinchi sekin xato ===")
oqilgan = 0
def sanab_oqi(fayl):
global oqilgan
for q in fayl:
oqilgan += 1
yield q
fayl = sanab_oqi(log_ochish())
sekin = next((q for q in fayl if " ERROR " in q and int(q.split()[-2]) > 90), None)
print(f" topildi: {sekin.strip() if sekin else None}")
print(f" o'qilgan qatorlar: {oqilgan:,} / 200,000")
print("\n=== 3. Quvur bosqichlari birma-bir ishlaydi ===")
qadamlar = []
def kuzat(nom, oqim):
for el in oqim:
qadamlar.append(nom)
yield el
manba = kuzat("o'qish", iter(["INFO a 1 ms", "ERROR b 95 ms", "ERROR c 99 ms"]))
filtr = kuzat("filtr", (q for q in manba if q.startswith("ERROR")))
sonlar = kuzat("son", (int(q.split()[-2]) for q in filtr))
birinchi = next(sonlar)
print(f" birinchi natija: {birinchi}")
print(f" bajarilgan qadamlar: {qadamlar}")
print(" ⭐ 3-qator hali o'qilmagan — faqat kerakli qism hisoblandi")
print("\n=== 4. itertools bilan bo'laklash ===")
def bolaklar(oqim, hajm):
it = iter(oqim)
while bolak := list(itertools.islice(it, hajm)):
yield bolak
xato_vaqtlari = xatolar_iterator(log_ochish())
for tartib, bolak in enumerate(bolaklar(xato_vaqtlari, 10_000), 1):
print(f" {tartib}-bo'lak: {len(bolak):>6,} ta, o'rtacha {sum(bolak) / len(bolak):.1f} ms")
print("\n=== 5. ⚠️ Quvurni ikkinchi marta ishlatish ===")
quvur = xatolar_iterator(log_ochish())
print(f" birinchi sum: {sum(quvur):,}")
print(f" ikkinchi sum: {sum(quvur):,} ⚠️ quvur tugagan")
print(" ✅ Yechim: quvurni funksiya qilib, har safar yangisini yarating")
print(f" qayta yaratilgan: {sum(xatolar_iterator(log_ochish())):,}")Natijaning muhim qismi:
=== 1. Xotira: ro'yxat vs iterator ===
ro'yxatlar bilan (sum) natija=1,919,917 xotira cho'qqisi= 19,175 KB
iteratorlar bilan (sum) natija=1,919,917 xotira cho'qqisi= 1 KB
=== 2. Erta to'xtash: birinchi sekin xato ===
topildi: 2026-09-14 12:34:00 ERROR so'rov #94 94 ms
o'qilgan qatorlar: 95 / 200,000
=== 3. Quvur bosqichlari birma-bir ishlaydi ===
birinchi natija: 95
bajarilgan qadamlar: ["o'qish", "o'qish", 'filtr', 'son']
⭐ 3-qator hali o'qilmagan — faqat kerakli qism hisoblandi
=== 4. itertools bilan bo'laklash ===
1-bo'lak: 10,000 ta, o'rtacha 48.0 ms
2-bo'lak: 10,000 ta, o'rtacha 48.0 ms
3-bo'lak: 10,000 ta, o'rtacha 48.0 ms
4-bo'lak: 10,000 ta, o'rtacha 48.0 ms
=== 5. ⚠️ Quvurni ikkinchi marta ishlatish ===
birinchi sum: 1,919,917
ikkinchi sum: 0 ⚠️ quvur tugagan
✅ Yechim: quvurni funksiya qilib, har safar yangisini yarating
qayta yaratilgan: 1,919,917Nima ko'rsatdi: 2.3, 2.4, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Iterable va iterator — bir narsa" | Iterable iterator beradi; iterator joyini eslaydi |
"range — iterator" |
range qayta ishlatiladigan iterable |
"map ro'yxat qaytaradi" |
Python 3 da bir martalik iterator qaytaradi |
"StopIteration — xato" |
"Tugadi" signali; for uni o'zi ushlaydi |
"x in it hech narsani o'zgartirmaydi" |
Iterator elementlarini topguncha iste'mol qiladi |
| "Iteratorni qayta boshlash mumkin" | Yo'q — yangi iterator yarating |
"isinstance(x, Iterable) hammasini aniqlaydi" |
Faqat __iter__ ni ko'radi; ishonchlisi — iter(x) |
| "Dangasa hisoblash doim yaxshi" | Xato kechikadi va qayta ishlatib bo'lmaydi |
6. Keng tarqalgan xatolar va yechimlari
1. Iteratorni ikki marta aylanish
sonlar = map(int, satrlar)
jami = sum(sonlar)
eng_katta = max(sonlar) # ❌ ValueError: max() iterable argument is empty
sonlar = list(map(int, satrlar)) # ✅2. Tekshirish iteratorni "yeydi"
if any(q.startswith("ERROR") for q in fayl):
for q in fayl: ... # ❌ qatorlarning bir qismi yo'q
qatorlar = list(fayl) # ✅ yoki bitta o'tishda ikkalasini qiling3. next() ni sukutsiz chaqirish
birinchi = next(x for x in r if x > 0) # ❌ topilmasa StopIteration
birinchi = next((x for x in r if x > 0), None) # ✅4. Lug'atni aylanishda o'zgartirish
for k in d:
if d[k] is None:
del d[k] # ❌ RuntimeError
for k in list(d): # ✅ kalitlar nusxasi
if d[k] is None:
del d[k]5. Ro'yxatdan element o'chirib aylanish
for x in r:
if shart(x): r.remove(x) # ❌ elementlar o'tkazib yuboriladi
r = [x for x in r if not shart(x)] # ✅6. Katta ma'lumotni keraksiz ro'yxatga aylantirish
sum([x.narx for x in buyurtmalar]) # ⚠️ oraliq ro'yxat
sum(x.narx for x in buyurtmalar) # ✅ generator ifodasi7. Belgi uchun iter() ga funksiya emas, qiymat berish
iter(f.read(4096), b"") # ❌ TypeError: iter(v, w): v must be callable
iter(lambda: f.read(4096), b"") # ✅8. while True bilan qo'lda StopIteration ushlash
it = iter(r)
while True:
try: x = next(it)
except StopIteration: break # ⚠️ ortiqcha murakkab
...
for x in r: ... # ✅ for buni o'zi qiladi7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 5.6-dars (o'tilgan):
forsikli — endi uning ichki mexanizmini bilasiz - 6.17-dars (o'tilgan): generator ifodalari — bir martalik iteratorlarning eng keng tarqalgani
- 8.14-dars (o'tilgan): konteyner protokoli va eski
__getitem__iteratsiyasi - 10.2-dars: o'z iterator sinflaringizni
__iter__va__next__bilan yozish - 10.3–10.5-darslar: generatorlar — iteratorni funksiya ko'rinishida yozish
- 15-qism:
itertoolsmoduli to'liq - 16-qism: katta fayllar (CSV, JSON Lines) bilan oqim sifatida ishlash
- 14-qism: asinxron iteratsiya (
__aiter__,async for)
8. Eng yaxshi amaliyotlar
Funksiya iterable qabul qilsa, uni faqat bir marta aylaning. Ikki marta kerak bo'lsa — boshida
list()ga aylantiring.Ro'yxat kerak bo'lmasa, generator ifodasi ishlating.
sum(x for x in ...)— oraliq ro'yxat yaratmaydi.next()ni sukut bilan chaqiring.next(it, None)—StopIterationning tasodifan tarqalishini oldini oladi.Bo'laklab o'qishda
iter(funksiya, belgi).while True+breakdan qisqa va aniq.Aylanayotgan to'plamni o'zgartirmang. Nusxa ustida aylaning yoki yangisini yasang.
Qayta ishlatiladigan quvurni funksiyaga o'rang. Har chaqiruvda yangi iterator — ikkinchi ishlatishda bo'sh natija bo'lmaydi.
Dangasa kodda xatolarni iste'mol joyida kuting.
map/generator yaratilganda emas, aylanilganda ko'tariladi."Iteratormi?" savoliga
iter(x) is xbilan javob bering.isinstancega qaraganda ishonchliroq.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
1. r = [1, 2, 3]
print(list(r), list(r))
2. m = map(str, [1, 2, 3])
print(list(m), list(m))
3. it = iter([1, 2, 3])
print(next(it), list(it))
4. it = iter("salom")
print("l" in it, "a" in it)
5. r = range(5)
print(sum(r), sum(r))
6. it = iter([1, 2, 3, 4, 5, 6])
print(list(zip(it, it)))
7. it = iter([])
print(next(it, "bo'sh"))
8. it = iter([10, 20])
print(iter(it) is it, iter([10, 20]) is iter([10, 20]))
9. g = (x * 2 for x in range(4))
print(3 in g, list(g))
10. sonlar = iter([5, 3, 0, 7, 1])
print(list(iter(lambda: next(sonlar), 0)), list(sonlar))
11. d = {"a": 1, "b": 2}
it = iter(d.items())
print(next(it), len(d))
12. from collections.abc import Iterator
print(isinstance(range(3), Iterator), isinstance(iter(range(3)), Iterator))Javoblar
[1, 2, 3] [1, 2, 3]— ro'yxat har safar yangi iterator beradi['1', '2', '3'] []—mapbir martalik1 [2, 3]—nextbitta elementni oldiTrue False—"l"qidirilgandas,a,liste'mol qilindi;"a"endi qolgano,michida yo'q10 10—rangeqayta ishlatiladi[(1, 2), (3, 4), (5, 6)]—zipbitta iteratordan navbatma-navbat oladibo'shTrue False— iterator o'zini qaytaradi; ro'yxatdan har safar yangi iteratorFalse []—x * 2doim juft, 3 topilmaydi va generator oxirigacha iste'mol qilinadi[5, 3] [7, 1]—0kelganda to'xtadi,0o'zi ham iste'mol qilingan('a', 1) 2— iterator olish lug'atni o'zgartirmaydiFalse True
Vazifa 2: Xatolarni tuzating
1. sonlar = map(float, qatorlar)
print(sum(sonlar) / len(list(sonlar)))
2. def bor_mi(oqim, qidiruv):
return qidiruv in oqim
fayl = open("log.txt")
if bor_mi(fayl, "ERROR\n"):
xatolar = [q for q in fayl if q == "ERROR\n"]
3. for kalit in sozlamalar:
if kalit.startswith("_"):
del sozlamalar[kalit]
4. birinchi_katta = next(x for x in narxlar if x > 1_000_000)
5. with open("rasm.png", "rb") as f:
for bolak in iter(f.read(8192), b""):
yubor(bolak)
6. juftlar = zip(royxat, royxat[1:])
print(len(juftlar))Javoblar
1. sonlar = list(map(float, qatorlar))
print(sum(sonlar) / len(sonlar))
2. qatorlar = list(fayl) # yoki bitta o'tishda sanash
if "ERROR\n" in qatorlar:
xatolar = [q for q in qatorlar if q == "ERROR\n"]
3. for kalit in list(sozlamalar):
if kalit.startswith("_"):
del sozlamalar[kalit]
4. birinchi_katta = next((x for x in narxlar if x > 1_000_000), None)
5. for bolak in iter(lambda: f.read(8192), b""):
6. juftlar = list(zip(royxat, royxat[1:])) # zip da len() yo'q
print(len(juftlar))Vazifa 3: for ni qo'lda yozing
mening_for(iterable, funksiya) funksiyasini yozing — u for siz, faqat iter(), next() va while bilan ishlasin:
- Har bir elementga
funksiya(element)ni qo'llasin - Nechta element aylanganini qaytarsin
funksiyaichidaStopIterationko'tarilsa, uni sikl tugashi deb qabul qilmasin (maslahat:next()ni alohidatryichida chaqiring)- Ro'yxat, lug'at, fayl va generator bilan sinab ko'ring
Vazifa 4: Xavfsiz statistika
statistika(sonlar) funksiyasini yozing: {"soni", "jami", "ortacha", "eng_kichik", "eng_katta"} qaytarsin.
- Ro'yxat berilganda ham, generator berilganda ham to'g'ri ishlasin
- Ma'lumotni bitta o'tishda hisoblasin (xotiraga yig'masdan)
- Bo'sh kirishda
ValueErroremas,Noneqiymatlar qaytarsin - 10 000 000 elementli generator bilan xotira
tracemallocbo'yicha 1 MB dan oshmasligini tekshiring
Vazifa 5: Bo'laklab o'quvchi
bolaklab(fayl_yoli, hajm=65536) funksiyasini yozing:
iter(funksiya, belgi)bilan faylni bo'laklab o'qisin- Har bo'lakni qaytaruvchi iterator bo'lsin
- Uning yordamida faylning SHA-256 xeshini hisoblang (
hashlib) - Natijani
hashlib.file_digest()(3.11+) bilan solishtiring
Vazifa 6: Juftlab va guruhlab
Faqat iteratorlar bilan (ro'yxatga aylantirmasdan) yozing:
juftlab([1, 2, 3, 4, 5, 6])→(1, 2), (3, 4), (5, 6)siljuvchi(["a", "b", "c", "d"], 2)→("a", "b"), ("b", "c"), ("c", "d")bolakla(range(10), 4)→[0, 1, 2, 3], [4, 5, 6, 7], [8, 9]- Har birini cheksiz oqim (
itertools.count()) bilanisliceorqali sinang
Vazifa 7: O'ylash
Python 2 da map, filter, zip, range, dict.keys() ro'yxat qaytarardi. Python 3 da ular dangasa obyektlarga aylandi. Bu qaror nega qabul qilindi? U qanday muammolarni hal qildi va qanday yangi muammolar tug'dirdi?
Javob
Qisqa javob: Python 3 "keraksiz ish qilmaslik"ni sukut qildi. Bu xotira va tezlikni sezilarli yaxshiladi, lekin "bir martalik iterator" tuzog'ini hamma dasturchining kundalik muammosiga aylantirdi.
1. Python 2 dagi holat
# Python 2
r = range(10000000) # 10M elementli RO'YXAT darhol yaratiladi
k = d.keys() # kalitlarning to'liq NUSXASI
m = map(f, katta) # hammasi darhol hisoblanadiDangasa variantlar alohida nomlar bilan mavjud edi: xrange, d.iterkeys(), itertools.imap, itertools.izip. Muammo shundaki, sukut tanlov qimmat edi, tejamli variantni esa ataylab eslab qolish kerak edi. Ko'pchilik range va map ni yozardi va xotirani behuda sarflardi.
2. Python 3 dagi qaror (PEP 3100 va "Python 3000")
Guido van Rossum va jamoa Python 3 da ikki tamoyilga amal qildi:
- Bir ish uchun bitta aniq yo'l —
range/xrange,keys/iterkeyskabi juftliklarni yo'qotish - Sukut arzon bo'lsin — kerak bo'lsa
list()bilan ro'yxat oling, lekin bu sizning ongli tanlovingiz
Natijada:
| Python 2 | Python 3 |
|---|---|
range() → ro'yxat |
range — dangasa, qayta ishlatiladigan ketma-ketlik |
xrange() |
olib tashlandi |
d.keys() → ro'yxat nusxasi |
d.keys() → ko'rinish (view) |
map, filter, zip → ro'yxat |
bir martalik iterator |
itertools.imap, izip |
olib tashlandi |
3. Hal qilingan muammolar
a) Xotira. for i in range(10**8) endi 800 MB emas, bir necha o'nlab bayt oladi.
b) Tezlik va erta to'xtash. next(x for x in map(f, katta) if shart(x)) birinchi mos element topilishi bilan to'xtaydi. Python 2 da map avval butun ro'yxatni hisoblab chiqardi.
c) Cheksiz oqimlar. zip(itertools.count(), fayl) kabi kombinatsiyalar tabiiy ishlaydi. Ro'yxat qaytaradigan zip cheksiz manba bilan osilib qolardi.
d) Ko'rinishlar doim yangi. d.keys() endi nusxa emas, lug'atga jonli oyna. Lug'at o'zgarsa, ko'rinish ham o'zgaradi va to'plam amallarini qo'llab-quvvatlaydi: d1.keys() & d2.keys().
4. Yangi muammolar
a) Bir martalik iterator tuzog'i. Bu darsning asosiy mavzusi. m = map(...) dan keyin ikkinchi sum(m) jimgina 0 qaytaradi. Xato xabari yo'q — faqat noto'g'ri natija. Bu eng yomon turdagi xato.
b) Kechiktirilgan xatolar. map(int, satrlar) dagi ValueError yaratish joyida emas, uzoqdagi iste'mol joyida chiqadi. Traceback xato "tug'ilgan" joyni emas, "topilgan" joyni ko'rsatadi.
c) Debug qilish qiyinlashdi. print(map(f, r)) endi natijani emas, <map object at 0x...> ni ko'rsatadi.
d) Python 2 → 3 ko'chirishdagi yashirin xatolar. Python 2 kodida k = d.keys() va keyin k.sort() yoki k[0] ishlatilgan bo'lsa, Python 3 da AttributeError yoki TypeError beradi. 2to3 vositasi ko'p joyga list(...) qo'shib chiqishga majbur bo'lgan.
5. Nega range iterator emas, lekin map — iterator?
Bu qarorning eng nozik joyi:
rangening uzunligi, indeksi vaintekshiruvi hisoblash bilan aniqlanadi (len(range(10**18))darhol ishlaydi,10**17 in range(10**18)ham). Unga qayta boshlanadigan ketma-ketlik bo'lish arzon.map(f, manba)esafni chaqirmasdan uzunligini ham, n-elementini ham bila olmaydi. Manba o'zi bir martalik bo'lishi mumkin (fayl, tarmoq). Uni qayta ishlatiladigan qilish uchun natijalarni saqlash kerak bo'lardi — bu esa dangasalikning butun ma'nosini yo'qotadi.
Qoida: natijani arzon qayta hisoblash mumkin bo'lsa — qayta ishlatiladigan obyekt; manbani qayta o'qib bo'lmasa — bir martalik iterator.
6. Boshqa tillar
| Til | Yondashuv |
|---|---|
| Java | Stream — bir martalik; ikkinchi terminal amal IllegalStateException beradi |
| C# | IEnumerable + LINQ — dangasa, lekin odatda qayta aylantirsa bo'ladi (har safar qayta hisoblaydi) |
| Rust | Iterator — bir martalik, lekin egalik tizimi ishlatilgan iteratorni ikkinchi marta ishlatishni kompilyatsiyada taqiqlaydi |
| JavaScript | massiv metodlari (map, filter) — darhol; generatorlar — bir martalik |
Rust bu muammoni eng yaxshi hal qilgan: xato ish vaqtida jimgina bo'sh natija emas, kompilyatsiya xatosi bo'ladi. Java esa hech bo'lmaganda ish vaqtida baland ovoz bilan xato beradi. Python esa jim qoladi — shuning uchun bu tuzoqni bilish Python dasturchisi uchun ayniqsa muhim.
7. Xulosa
- Python 3 dangasalikni sukut qildi: xotira, tezlik va cheksiz oqimlar yutdi
- Narxi — bir martalik iterator tuzog'i va kechiktirilgan xatolar
rangeva lug'at ko'rinishlari qayta ishlatiladi, chunki ularni qayta hisoblash arzonmap,filter,zip, generator, fayl — bir martalik, chunki manbani qayta o'qib bo'lmasligi mumkin- Amaliy qoida: ikki marta kerak bo'lsa —
list()qiling, bir marta kerak bo'lsa — dangasa qoldiring
Nimani mustahkamlaydi: 2.1–2.7-bo'limlar.
Xulosa
Bu darsda Python'dagi iteratsiyaning poydevorini o'rgandik.
Eng muhim uch fikr:
Iterable iterator beradi, iterator esa joyini eslaydi. Ro'yxat, lug'at, satr va
range— qayta ishlatiladigan iterable: harforulardan yangi iterator oladi.map,filter,zip, generator va fayl esa iteratorning o'zi — ular faqat oldinga yuradi va bir marta tugaydi. "Bu obyekt bir martalikmi?" degan savolgaiter(x) is xjavob beradi.for— buiter(),next()vaStopIterationning qisqa yozuvi. Sikl boshida bitta iterator olinadi, elementlar birma-bir so'raladi,StopIterationesa xato emas, "tugadi" signali.list(),sum(),in, ochish vazip— hammasi shu protokolda ishlaydi.next(it, sukut)vaiter(funksiya, belgi)bu protokolning amaliy qulayliklari.Dangasalik xotira va vaqtni tejaydi, lekin ikki narx to'laysiz. Birinchisi — iteratorni ikkinchi marta ishlatganda jimgina bo'sh natija. Ikkinchisi — xatolarning yaratilgan joyda emas, iste'mol qilingan joyda chiqishi. Qoida oddiy: natija ikki marta kerak bo'lsa —
list()ga aylantiring.
Keyingi darsda __iter__ va __next__ metodlarini o'zimiz yozib, maxsus iterator sinflarini yaratamiz: qayta ishlatiladigan konteyner bilan bir martalik iteratorni qanday to'g'ri ajratish kerakligini ko'ramiz.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!