IlmHamroh
Python kursi/Ilgor til imkoniyatlari4/17-dars27 daqiqa
Mundarija (22)

10.4-dars: Generator amaliyoti

10-QISM — ILG'OR TIL IMKONIYATLARI · 4-dars


1. Kirish va motivatsiya

Tasavvur qiling: har kuni 20 GB lik veb-server logi keladi. Vazifa — oxirgi soatdagi 500 xatolarning eng sekin 10 tasini topish.

Birinchi urinish:

python
qatorlar = open("access.log").readlines()          # ⚠️ 20 GB xotiraga
yozuvlar = [tahlil(q) for q in qatorlar]           # ⚠️ yana 20+ GB
xatolar = [y for y in yozuvlar if y.kod == 500]
eng_sekin = sorted(xatolar, key=lambda y: y.vaqt)[-10:]

Kompyuter xotirasi tugaydi va dastur yiqiladi.

Generatorlar bilan:

python
qatorlar = open("access.log")                      # qatorma-qator
yozuvlar = (tahlil(q) for q in qatorlar)
xatolar = (y for y in yozuvlar if y.kod == 500)
eng_sekin = heapq.nlargest(10, xatolar, key=lambda y: y.vaqt)

Xuddi o'sha mantiq, lekin xotirada bir vaqtning o'zida bitta qator va 10 ta natija turadi. Fayl 20 GB bo'ladimi, 200 GB mi — farqi yo'q.

Bu naqsh — generator quvuri (pipeline). U Unix'dagi cat access.log | grep 500 | sort | head ning Python'dagi ekvivalenti: har bosqich oldingisidan element oladi, qayta ishlaydi va keyingisiga uzatadi.

O'tgan darsda generator qanday ishlashini o'rgandik. Bu darsda ular bilan qanday ishlashni o'rganamiz.

Bu darsda:

  • Generator quvurlari: manba → bosqichlar → yakunlovchi
  • Quvurda elementlar qanday "oqadi"
  • itertools bilan generatorlar
  • Tayyor retseptlar: bo'laklash, siljuvchi oyna, takrorsiz, birlashtirish
  • tee va groupby tuzoqlari
  • Quvurda xatolar bilan ishlash
  • Qachon generator kerak emas

2. Nazariya — chuqur tushuntirish

2.1. Quvur tuzilishi

Har quvur uch turdagi bosqichdan tashkil topadi:

Bosqich Nima qiladi Misol
Manba Elementlarni ishlab chiqaradi fayl, range, API, count()
Oraliq Element oladi, element beradi filtr, o'zgartirish, tahlil
Yakunlovchi Hammasini iste'mol qiladi sum, list, max, for, fayl yozish
python
def qatorlar(yol):                          # manba
    with open(yol, encoding="utf-8") as f:
        yield from f

def tozala(oqim):                           # oraliq
    for q in oqim:
        q = q.strip()
        if q and not q.startswith("#"):
            yield q

def sonlar(oqim):                           # oraliq
    for q in oqim:
        yield int(q)

jami = sum(sonlar(tozala(qatorlar("data.txt"))))    # yakunlovchi

Yakunlovchi bo'lmasa, hech narsa bajarilmaydi. sonlar(tozala(...)) shunchaki generatorlar zanjirini quradi — fayl hatto ochilmaydi.

2.2. Elementlar qanday oqadi

Ro'yxatlar bilan ishlash bosqichma-bosqich bo'ladi: avval hamma qatorlar o'qiladi, keyin hammasi tozalanadi, keyin hammasi songa aylanadi.

Generator quvurida esa elementma-element: birinchi qator barcha bosqichlardan o'tadi, keyin ikkinchisi va hokazo.

Ro'yxatlar:                    Generatorlar:
o'qi 1, o'qi 2, o'qi 3         o'qi 1 → tozala 1 → son 1
tozala 1, tozala 2, tozala 3   o'qi 2 → tozala 2 → son 2
son 1, son 2, son 3            o'qi 3 → tozala 3 → son 3

Buning oqibatlari:

  1. Xotira — bir vaqtda bitta element
  2. Erta to'xtash — yakunlovchi to'xtasa, manba ham to'xtaydi
  3. Birinchi natija tez — hammasini kutmasdan
  4. Xato kechikadi — 1 000 000-qatordagi xato faqat shunga yetganda chiqadi

2.3. Bosqich turlari: funksiya yoki ifoda

Oddiy bosqich uchun generator ifodasi yetarli:

python
tozalangan = (q.strip() for q in oqim if q.strip())

Generator funksiya kerak bo'ladi, agar bosqichda:

  • holat bo'lsa (hisoblagich, oldingi element, bufer)
  • bir elementdan bir nechta yoki nol element chiqsa
  • try/except kerak bo'lsa
  • nomi va hujjati kerak bo'lsa (qayta ishlatiladigan bosqich)

2.4. itertools — tayyor bosqichlar

Funksiya Nima qiladi
islice(it, n) / islice(it, a, b) Kesish — it[a:b] ning dangasa varianti
takewhile(shart, it) Shart bajarilguncha oladi
dropwhile(shart, it) Shart bajarilguncha tashlaydi, keyin hammasini beradi
chain(a, b, ...) Oqimlarni ketma-ket ulaydi
chain.from_iterable(oqimlar) Oqimlar oqimini tekislaydi
groupby(it, key) Ketma-ket teng elementlarni guruhlaydi
accumulate(it, f) Yig'ma natijalar (jami, maksimum)
pairwise(it) (3.10+) (a, b), (b, c), ...
batched(it, n) (3.12+) n talik kortejlar
tee(it, n) Bitta iteratordan n ta mustaqil nusxa
count(), cycle(), repeat() Cheksiz manbalar
compress(it, belgilar) Belgi rost bo'lganlarini oladi
starmap(f, it) f(*el)

To'liq itertools 15-qismda. Bu yerda — generatorlar bilan eng ko'p ishlatiladiganlari.

2.5. groupby tuzog'i

groupby SQL'dagi GROUP BY emas. U faqat yonma-yon turgan teng elementlarni birlashtiradi:

python
from itertools import groupby

[(k, len(list(g))) for k, g in groupby("aabba")]
# [('a', 2), ('b', 2), ('a', 1)]    ⚠️ 'a' ikki guruhda

To'liq guruhlash uchun avval shu kalit bo'yicha saralang. Oqim juda katta bo'lsa — saralash o'rniga lug'at ishlating.

Ikkinchi tuzoq: guruh iteratori keyingi guruhga o'tishi bilan yaroqsiz bo'ladi:

python
guruhlar = list(groupby("aabb"))
[list(g) for k, g in guruhlar]      # [[], []]  ⚠️ hammasi bo'sh (Python 3.14)

Guruhni darhol iste'mol qiling: {k: list(g) for k, g in groupby(...)}.

2.6. tee tuzog'i

tee bitta iteratordan bir nechta nusxa yasaydi. Lekin nusxalardan biri oldinga ketsa, orqada qolgani uchun o'tkazib yuborilgan elementlar xotirada saqlanadi:

python
a, b = tee(katta_oqim)
max(a)                          # a oxirigacha bordi
min(b)                          # ⚠️ butun oqim xotirada saqlangan edi

Bundan tashqari, tee dan keyin asl iteratorni ishlatmang — nusxalar buziladi.

Ikki natija kerak bo'lsa, ko'pincha bitta o'tishda hisoblash yaxshiroq (Misol 2).

2.7. Quvurdagi xatolar

Dangasa quvurda xato iste'mol paytida, ko'pincha yakunlovchi ichida chiqadi. Uch strategiya bor:

Strategiya Qachon
To'xtash — xatoni o'tkazib yuborish Ma'lumot sifati kafolatlangan, xato — bug
O'tkazib yuborish — bosqich ichida ushlab, davom etish Bir nechta buzuq yozuv kutiladi
Ajratish — xatolarni alohida oqimga yig'ish Buzuqlar hisobotda kerak
python
def xavfsiz_son(oqim, xatolar):
    for tartib, q in enumerate(oqim, 1):
        try:
            yield int(q)
        except ValueError as e:
            xatolar.append((tartib, q, e))      # ⭐ davom etamiz

2.8. Qachon generator kerak emas

  • Ma'lumot kichik va bir necha marta ishlatiladi — ro'yxat soddaroq
  • len(), indeks yoki teskari tartib kerak
  • Natijani saralash kerak — sorted() baribir hammasini yig'adi
  • Bosqichlar orasida tasodifiy kirish kerak
  • Debug paytida oraliq natijalarni ko'rish muhim

Qoida: ma'lumot xotiraga sig'masa yoki erta to'xtash kerak bo'lsa — generator; aks holda — o'qilishi osonrog'i.


3. Tez ma'lumotnoma

Quvur

python
manba = (...)                        # fayl, range, API
bosqich1 = (f(x) for x in manba)
bosqich2 = (x for x in bosqich1 if shart(x))
natija = sum(bosqich2)               # ⭐ faqat shu yerda ishlaydi

Retseptlar

python
next(it, None)                          birinchi element
deque(it, maxlen=1)                     oxirgi element (xotirasiz)
deque(it, maxlen=0)                     oxirigacha iste'mol qilish
islice(it, n)                           birinchi n ta
batched(it, n)                          n talik bo'laklar (3.12+)
pairwise(it)                            qo'shni juftlar (3.10+)
chain.from_iterable(ichma_ich)          bir qavat tekislash
heapq.merge(a, b)                       saralangan oqimlarni birlashtirish
heapq.nlargest(n, it, key)              eng katta n ta (xotira O(n))

Tuzoqlar

groupby                   faqat yonma-yon; guruhni darhol iste'mol qiling
tee                       orqada qolgan nusxa uchun hammasi xotirada
yakunlovchi yo'q          hech narsa bajarilmaydi
sorted(generator)         dangasalik yo'qoladi — hammasi yig'iladi

4. Batafsil misollar

Misol 1 — Quvurda elementlar qanday oqadi

python
"""Ro'yxat va generator quvurlarini bajarilish tartibi bo'yicha solishtirish."""

tartib = []


def manba(qatorlar):
    for q in qatorlar:
        tartib.append(f"o'qi:{q.strip()!r}")
        yield q


def tozala(oqim):
    for q in oqim:
        q = q.strip()
        tartib.append(f"tozala:{q!r}")
        if q and not q.startswith("#"):
            yield q


def son(oqim):
    for q in oqim:
        tartib.append(f"son:{q}")
        yield int(q)


FAYL = ["10\n", "# izoh\n", "20\n", "\n", "30\n"]

print("=== 1. Ro'yxatlar bilan: bosqichma-bosqich ===")
tartib.clear()
a = list(manba(FAYL))
b = list(tozala(a))
c = list(son(b))
print(f"  natija: {sum(c)}")
for qadam in tartib:
    print(f"    {qadam}")

print("\n=== 2. Generatorlar bilan: elementma-element ===")
tartib.clear()
quvur = son(tozala(manba(FAYL)))
print(f"  quvur qurildi, bajarilgan qadamlar: {len(tartib)}")
print(f"  natija: {sum(quvur)}")
for qadam in tartib:
    print(f"    {qadam}")

print("\n=== 3. Erta to'xtash manbani ham to'xtatadi ===")
tartib.clear()
quvur = son(tozala(manba(FAYL)))
birinchi_katta = next(x for x in quvur if x > 15)
print(f"  15 dan katta birinchisi: {birinchi_katta}")
print(f"  bajarilgan qadamlar: {tartib}")
print(f"  ⭐ '30' hech qachon o'qilmadi")

print("\n=== 4. Yakunlovchisiz — hech narsa ===")
tartib.clear()
quvur = son(tozala(manba(["1\n", "x\n"])))
print(f"  xato bo'lishi kerak bo'lgan quvur qurildi, qadamlar: {len(tartib)}")
try:
    list(quvur)
except ValueError as e:
    print(f"  faqat iste'molda: ❌ ValueError: {e}")
    print(f"  xatogacha qadamlar: {tartib}")

Natijaning muhim qismi:

text
=== 1. Ro'yxatlar bilan: bosqichma-bosqich ===
  natija: 60
    o'qi:'10'
    o'qi:'# izoh'
    o'qi:'20'
    o'qi:''
    o'qi:'30'
    tozala:'10'
    tozala:'# izoh'
    tozala:'20'
    tozala:''
    tozala:'30'
    son:10
    son:20
    son:30

=== 2. Generatorlar bilan: elementma-element ===
  quvur qurildi, bajarilgan qadamlar: 0
  natija: 60
    o'qi:'10'
    tozala:'10'
    son:10
    o'qi:'# izoh'
    tozala:'# izoh'
    o'qi:'20'
    tozala:'20'
    son:20
    o'qi:''
    tozala:''
    o'qi:'30'
    tozala:'30'
    son:30

=== 3. Erta to'xtash manbani ham to'xtatadi ===
  15 dan katta birinchisi: 20
  bajarilgan qadamlar: ["o'qi:'10'", "tozala:'10'", 'son:10', "o'qi:'# izoh'", "tozala:'# izoh'", "o'qi:'20'", "tozala:'20'", 'son:20']
  ⭐ '30' hech qachon o'qilmadi

=== 4. Yakunlovchisiz — hech narsa ===
  xato bo'lishi kerak bo'lgan quvur qurildi, qadamlar: 0
  faqat iste'molda: ❌ ValueError: invalid literal for int() with base 10: 'x'
  xatogacha qadamlar: ["o'qi:'1'", "tozala:'1'", 'son:1', "o'qi:'x'", "tozala:'x'", 'son:x']

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

Misol 2 — itertools bilan generatorlar va ularning tuzoqlari

python
"""islice, takewhile, dropwhile, groupby, tee, batched, pairwise — amalda."""

import itertools
import tracemalloc
from collections import defaultdict

print("=== 1. Cheksiz manbani cheklash ===")


def tub_sonlar():
    topilgan = []
    for n in itertools.count(2):
        if all(n % t for t in topilgan if t * t <= n):
            topilgan.append(n)
            yield n


print(f"  birinchi 10 tub: {list(itertools.islice(tub_sonlar(), 10))}")
print(f"  100 dan kichiklar: {list(itertools.takewhile(lambda x: x < 100, tub_sonlar()))[-5:]} (oxirgi 5)")
print(f"  1000 dan keyingi 3 ta: {list(itertools.islice(itertools.dropwhile(lambda x: x < 1000, tub_sonlar()), 3))}")

print("\n=== 2. ⚠️ groupby faqat yonma-yonlarni birlashtiradi ===")
SOTUVLAR = [("olma", 3), ("anor", 1), ("olma", 2), ("olma", 5), ("anor", 4)]
yomon = [(k, sum(s for _, s in g)) for k, g in itertools.groupby(SOTUVLAR, key=lambda x: x[0])]
print(f"  saralanmagan: {yomon}")
saralangan = sorted(SOTUVLAR, key=lambda x: x[0])
togri = [(k, sum(s for _, s in g)) for k, g in itertools.groupby(saralangan, key=lambda x: x[0])]
print(f"  saralangan:   {togri}")
lugat = defaultdict(int)
for mahsulot, soni in SOTUVLAR:
    lugat[mahsulot] += soni
print(f"  lug'at bilan (saralashsiz): {dict(lugat)}")

print("\n=== 3. ⚠️ groupby guruhlarini keyin iste'mol qilish ===")
guruhlar = list(itertools.groupby("aaabbc"))
print(f"  list(groupby) dan keyin: {[(k, list(g)) for k, g in guruhlar]}")
print(f"  darhol iste'mol:         {[(k, list(g)) for k, g in itertools.groupby('aaabbc')]}")

print("\n=== 4. ⚠️ tee xotirasi ===")


def katta_oqim(n=300_000):
    for i in range(n):
        yield i * 3 % 1_000_003


tracemalloc.start()
a, b = itertools.tee(katta_oqim())
eng_katta = max(a)
_, tepa_tee = tracemalloc.get_traced_memory()
eng_kichik = min(b)
tracemalloc.stop()

tracemalloc.start()
eng_katta2, eng_kichik2 = float("-inf"), float("inf")
for x in katta_oqim():
    eng_katta2 = max(eng_katta2, x)
    eng_kichik2 = min(eng_kichik2, x)
_, tepa_bitta = tracemalloc.get_traced_memory()
tracemalloc.stop()

print(f"  tee (max, keyin min): {eng_katta}, {eng_kichik}   xotira cho'qqisi: {tepa_tee / 1024:,.0f} KB")
print(f"  bitta o'tishda:       {eng_katta2}, {eng_kichik2}   xotira cho'qqisi: {tepa_bitta / 1024:,.0f} KB")

print("\n=== 5. batched, pairwise, accumulate ===")
harorat = [18, 21, 19, 24, 26, 25, 22]
print(f"  batched(3):  {list(itertools.batched(harorat, 3))}")
print(f"  o'zgarishlar (pairwise): {[b - a for a, b in itertools.pairwise(harorat)]}")
print(f"  yig'ma maksimum:         {list(itertools.accumulate(harorat, max))}")
print(f"  yig'ma jami:             {list(itertools.accumulate(harorat))}")

print("\n=== 6. chain.from_iterable — fayllar oqimini tekislash ===")
FAYLLAR = {"yanvar.csv": ["a,1", "b,2"], "fevral.csv": ["c,3"], "mart.csv": []}


def fayl_qatorlari(nom):
    print(f"    ochildi: {nom}")
    yield from FAYLLAR[nom]


barchasi = itertools.chain.from_iterable(fayl_qatorlari(n) for n in FAYLLAR)
print(f"  birinchi qator: {next(barchasi)}   ⭐ faqat birinchi fayl ochildi")
print(f"  qolganlari: {list(barchasi)}")

Natijaning muhim qismi:

text
=== 1. Cheksiz manbani cheklash ===
  birinchi 10 tub: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
  100 dan kichiklar: [73, 79, 83, 89, 97] (oxirgi 5)
  1000 dan keyingi 3 ta: [1009, 1013, 1019]

=== 2. ⚠️ groupby faqat yonma-yonlarni birlashtiradi ===
  saralanmagan: [('olma', 3), ('anor', 1), ('olma', 7), ('anor', 4)]
  saralangan:   [('anor', 5), ('olma', 10)]
  lug'at bilan (saralashsiz): {'olma': 10, 'anor': 5}

=== 3. ⚠️ groupby guruhlarini keyin iste'mol qilish ===
  list(groupby) dan keyin: [('a', []), ('b', []), ('c', [])]
  darhol iste'mol:         [('a', ['a', 'a', 'a']), ('b', ['b', 'b']), ('c', ['c'])]

=== 4. ⚠️ tee xotirasi ===
  tee (max, keyin min): 899997, 0   xotira cho'qqisi: 12,002 KB
  bitta o'tishda:       899997, 0   xotira cho'qqisi: 0 KB

=== 5. batched, pairwise, accumulate ===
  batched(3):  [(18, 21, 19), (24, 26, 25), (22,)]
  o'zgarishlar (pairwise): [3, -2, 5, 2, -1, -3]
  yig'ma maksimum:         [18, 21, 21, 24, 26, 26, 26]
  yig'ma jami:             [18, 39, 58, 82, 108, 133, 155]

=== 6. chain.from_iterable — fayllar oqimini tekislash ===
    ochildi: yanvar.csv
  birinchi qator: a,1   ⭐ faqat birinchi fayl ochildi
    ochildi: fevral.csv
    ochildi: mart.csv
  qolganlari: ['b,2', 'c,3']

Nima ko'rsatdi: 2.4, 2.5, 2.6-bo'limlar.

Misol 3 — Retseptlar kutubxonasi

python
"""Kundalik ishda kerak bo'ladigan generator retseptlari va ularning sinovlari."""

import heapq
import itertools
from collections import deque


def bolaklar(oqim, hajm):
    """[1..7], 3 → [1,2,3], [4,5,6], [7]  — batched ning ro'yxat varianti."""
    it = iter(oqim)
    while bolak := list(itertools.islice(it, hajm)):
        yield bolak


def siljuvchi_oyna(oqim, hajm):
    """[1,2,3,4], 3 → (1,2,3), (2,3,4)."""
    it = iter(oqim)
    oyna = deque(itertools.islice(it, hajm), maxlen=hajm)
    if len(oyna) == hajm:
        yield tuple(oyna)
    for el in it:
        oyna.append(el)
        yield tuple(oyna)


def takrorsiz(oqim, kalit=None):
    """Birinchi uchragan tartibni saqlab takrorlarni tashlaydi."""
    korilgan = set()
    for el in oqim:
        k = el if kalit is None else kalit(el)
        if k not in korilgan:
            korilgan.add(k)
            yield el


def navbatma_navbat(*oqimlar):
    """'ABC', 'D', 'EF' → A D E B F C."""
    faol = deque(iter(o) for o in oqimlar)
    while faol:
        it = faol.popleft()
        try:
            yield next(it)
        except StopIteration:
            continue
        faol.append(it)


def oxirgi(oqim, sukut=None):
    """Oxirgi elementni xotiraga yig'masdan."""
    d = deque(oqim, maxlen=1)
    return d[0] if d else sukut


def yetkaz(oqim, qadam):
    """Har `qadam` elementda bir marta progress chiqaradi, elementlarni o'zgartirmaydi."""
    for tartib, el in enumerate(oqim, 1):
        if tartib % qadam == 0:
            print(f"    ... {tartib:,} ta ishlandi")
        yield el


SINOVLAR = [
    ("bolaklar", list(bolaklar(range(1, 8), 3)), [[1, 2, 3], [4, 5, 6], [7]]),
    ("bolaklar (bo'sh)", list(bolaklar([], 3)), []),
    ("siljuvchi_oyna", list(siljuvchi_oyna([1, 2, 3, 4], 3)), [(1, 2, 3), (2, 3, 4)]),
    ("siljuvchi_oyna (qisqa)", list(siljuvchi_oyna([1, 2], 3)), []),
    ("takrorsiz", list(takrorsiz("abracadabra")), ["a", "b", "r", "c", "d"]),
    ("takrorsiz (kalit)", list(takrorsiz(["Olma", "olma", "ANOR"], str.lower)), ["Olma", "ANOR"]),
    ("navbatma_navbat", "".join(navbatma_navbat("ABC", "D", "EF")), "ADEBFC"),
    ("oxirgi", oxirgi(x * x for x in range(1_000_000)), 999_998_000_001),
    ("oxirgi (bo'sh)", oxirgi(iter([]), "yo'q"), "yo'q"),
]

print("=== 1. Retseptlar sinovi ===")
for nom, haqiqiy, kutilgan in SINOVLAR:
    belgi = "✅" if haqiqiy == kutilgan else "❌"
    print(f"  {belgi} {nom:<24} → {haqiqiy}")

print("\n=== 2. Saralangan oqimlarni birlashtirish (heapq.merge) ===")
toshkent = [("08:01", "T", 120), ("08:05", "T", 90), ("08:20", "T", 300)]
samarqand = [("08:02", "S", 50), ("08:15", "S", 75)]
buxoro = [("08:00", "B", 10), ("08:30", "B", 40)]
for vaqt, filial, summa in heapq.merge(toshkent, samarqand, buxoro):
    print(f"  {vaqt} {filial} {summa:>4}")

print("\n=== 3. Siljuvchi o'rtacha — oqimda ===")
narxlar = [100, 102, 101, 105, 110, 108, 115]
for oyna in siljuvchi_oyna(narxlar, 3):
    print(f"  {oyna} → o'rtacha {sum(oyna) / 3:.1f}")

print("\n=== 4. Progress chiqaruvchi bosqich ===")
jami = sum(yetkaz((x for x in range(250_000)), 100_000))
print(f"  jami: {jami:,}")

print("\n=== 5. Eng katta N ta — heapq.nlargest xotirasi ===")
import tracemalloc

tracemalloc.start()
top = heapq.nlargest(3, (x * 7919 % 1_000_003 for x in range(500_000)))
_, tepa = tracemalloc.get_traced_memory()
tracemalloc.stop()
tracemalloc.start()
top2 = sorted([x * 7919 % 1_000_003 for x in range(500_000)], reverse=True)[:3]
_, tepa2 = tracemalloc.get_traced_memory()
tracemalloc.stop()
print(f"  nlargest(generator): {top}   xotira: {tepa / 1024:,.0f} KB")
print(f"  sorted(ro'yxat)[:3]: {top2}   xotira: {tepa2 / 1024:,.0f} KB")

Natijaning muhim qismi:

text
=== 1. Retseptlar sinovi ===
  ✅ bolaklar                 → [[1, 2, 3], [4, 5, 6], [7]]
  ✅ bolaklar (bo'sh)         → []
  ✅ siljuvchi_oyna           → [(1, 2, 3), (2, 3, 4)]
  ✅ siljuvchi_oyna (qisqa)   → []
  ✅ takrorsiz                → ['a', 'b', 'r', 'c', 'd']
  ✅ takrorsiz (kalit)        → ['Olma', 'ANOR']
  ✅ navbatma_navbat          → ADEBFC
  ✅ oxirgi                   → 999998000001
  ✅ oxirgi (bo'sh)           → yo'q

=== 2. Saralangan oqimlarni birlashtirish (heapq.merge) ===
  08:00 B   10
  08:01 T  120
  08:02 S   50
  08:05 T   90
  08:15 S   75
  08:20 T  300
  08:30 B   40

=== 3. Siljuvchi o'rtacha — oqimda ===
  (100, 102, 101) → o'rtacha 101.0
  (102, 101, 105) → o'rtacha 102.7
  (101, 105, 110) → o'rtacha 105.3
  (105, 110, 108) → o'rtacha 107.7
  (110, 108, 115) → o'rtacha 111.0

=== 4. Progress chiqaruvchi bosqich ===
    ... 100,000 ta ishlandi
    ... 200,000 ta ishlandi
  jami: 31,249,875,000

=== 5. Eng katta N ta — heapq.nlargest xotirasi ===
  nlargest(generator): [1000002, 1000000, 999999]   xotira: 1 KB
  sorted(ro'yxat)[:3]: [1000002, 1000000, 999999]   xotira: 25,549 KB

Nima ko'rsatdi: 2.3, 2.4-bo'limlar va 3-bo'limdagi retseptlar.

Misol 4 — Amaliy: bir nechta filialdan oqimli sotuv hisoboti

python
"""Uch filialning CSV oqimlari → tahlil → tekshirish → kunlik hisobot. Xatolar alohida yig'iladi."""

import heapq
import io
import itertools
import tracemalloc
from collections import defaultdict
from dataclasses import dataclass
from datetime import date


FILIAL_URUG = {"TSH": 0, "SAM": 123_457, "BUX": 345_679}


def filial_fayli(filial, kunlar, har_kun):
    """Sun'iy CSV: har filialda ba'zi qatorlar ataylab buzuq."""
    qatorlar = ["sana,chek,summa\n"]
    urug = FILIAL_URUG[filial]
    for kun in range(1, kunlar + 1):
        for i in range(har_kun):
            chek = f"{filial}-{kun:02d}-{i:05d}"
            if i % 997 == 13:
                qatorlar.append(f"2026-09-{kun:02d},{chek},noma'lum\n")      # buzuq summa
            elif i % 1499 == 7:
                qatorlar.append(f"2026-09-{kun:02d},{chek}\n")               # ustun yetishmaydi
            else:
                summa = (i * 7919 + kun * 104729 + urug) % (380_000 + urug // 3) + 10_000
                qatorlar.append(f"2026-09-{kun:02d},{chek},{summa}\n")
    return io.StringIO("".join(qatorlar))


@dataclass(frozen=True, slots=True)
class Sotuv:
    sana: date
    filial: str
    chek: str
    summa: int


# ── Bosqichlar ──

def csv_qatorlari(filial, fayl):
    sarlavha = next(fayl, None)
    if sarlavha is None:
        return
    for raqam, qator in enumerate(fayl, 2):
        yield filial, raqam, qator.rstrip("\n")


def tahlil(oqim, xatolar):
    for filial, raqam, qator in oqim:
        qismlar = qator.split(",")
        try:
            if len(qismlar) != 3:
                raise ValueError(f"{len(qismlar)} ustun, 3 kutilgan")
            yil, oy, kun = map(int, qismlar[0].split("-"))
            yield Sotuv(date(yil, oy, kun), filial, qismlar[1], int(qismlar[2]))
        except ValueError as e:
            xatolar[filial].append((raqam, str(e)))


def sana_boyicha(oqimlar):
    """Har filial fayli sana bo'yicha saralangan — ularni birlashtiramiz."""
    return heapq.merge(*oqimlar, key=lambda s: s.sana)


def kunlik_hisobot(sotuvlar):
    for kun, guruh in itertools.groupby(sotuvlar, key=lambda s: s.sana):
        jami, soni, filiallar = 0, 0, defaultdict(int)
        eng_katta = None
        for s in guruh:
            jami += s.summa
            soni += 1
            filiallar[s.filial] += s.summa
            if eng_katta is None or s.summa > eng_katta.summa:
                eng_katta = s
        yield kun, soni, jami, dict(filiallar), eng_katta


FILIALLAR = ["TSH", "SAM", "BUX"]
KUNLAR, HAR_KUN = 5, 20_000

xatolar = defaultdict(list)
fayllar = {f: filial_fayli(f, KUNLAR, HAR_KUN) for f in FILIALLAR}

tracemalloc.start()
quvurlar = [tahlil(csv_qatorlari(f, fayl), xatolar) for f, fayl in fayllar.items()]
hisobot = list(kunlik_hisobot(sana_boyicha(quvurlar)))
_, tepa = tracemalloc.get_traced_memory()
tracemalloc.stop()

print("=== 1. Kunlik hisobot ===")
print(f"  {'Sana':<11} {'Cheklar':>8} {'Jami (mln)':>11}  {'TSH':>7} {'SAM':>7} {'BUX':>7}  Eng katta chek")
print("  " + "─" * 84)
for kun, soni, jami, filiallar, eng_katta in hisobot:
    f = {k: v / 1e6 for k, v in filiallar.items()}
    print(f"  {kun}  {soni:>8,} {jami / 1e6:>11,.1f}  {f['TSH']:>7,.1f} {f['SAM']:>7,.1f} "
          f"{f['BUX']:>7,.1f}  {eng_katta.chek} ({eng_katta.summa:,})")

print("\n=== 2. Xatolar filial bo'yicha ===")
for filial in FILIALLAR:
    royxat = xatolar[filial]
    print(f"  {filial}: {len(royxat)} ta buzuq qator, birinchisi: {royxat[0]}")

jami_qator = KUNLAR * HAR_KUN * len(FILIALLAR)
jami_xato = sum(len(v) for v in xatolar.values())
print(f"\n=== 3. Xulosa ===")
print(f"  jami qator: {jami_qator:,}, to'g'ri: {sum(s for _, s, *_ in hisobot):,}, buzuq: {jami_xato:,}")
print(f"  quvur xotira cho'qqisi: {tepa / 1_048_576:.2f} MB")

print("\n=== 4. Butun davrdagi eng katta 3 chek ===")
for f in fayllar.values():
    f.seek(0)
eng_kattalar = heapq.nlargest(
    3,
    itertools.chain.from_iterable(
        tahlil(csv_qatorlari(fl, fayl), defaultdict(list)) for fl, fayl in fayllar.items()
    ),
    key=lambda s: s.summa,
)
for s in eng_kattalar:
    print(f"  {s.chek}  {s.summa:,} so'm")

Natijaning muhim qismi:

text
=== 1. Kunlik hisobot ===
  Sana         Cheklar  Jami (mln)      TSH     SAM     BUX  Eng katta chek
  ────────────────────────────────────────────────────────────────────────────────────
  2026-09-01    59,895    13,539.2  3,995.2 4,404.0 5,140.0  BUX-01-08323 (505,187)
  2026-09-02    59,895    13,541.8  3,993.0 4,404.8 5,144.0  BUX-02-06121 (505,188)
  2026-09-03    59,895    13,541.6  3,991.3 4,404.2 5,146.1  BUX-03-03919 (505,189)
  2026-09-04    59,895    13,538.8  3,991.8 4,403.3 5,143.6  BUX-04-01717 (505,190)
  2026-09-05    59,895    13,537.6  3,994.6 4,403.2 5,139.8  BUX-05-08958 (505,182)

=== 2. Xatolar filial bo'yicha ===
  TSH: 175 ta buzuq qator, birinchisi: (9, '2 ustun, 3 kutilgan')
  SAM: 175 ta buzuq qator, birinchisi: (9, '2 ustun, 3 kutilgan')
  BUX: 175 ta buzuq qator, birinchisi: (9, '2 ustun, 3 kutilgan')

=== 3. Xulosa ===
  jami qator: 300,000, to'g'ri: 299,475, buzuq: 525
  quvur xotira cho'qqisi: 0.09 MB

=== 4. Butun davrdagi eng katta 3 chek ===
  BUX-04-01717  505,190 so'm
  BUX-03-03919  505,189 so'm
  BUX-02-06121  505,188 so'm

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


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

Noto'g'ri fikr To'g'risi
"Quvur qurilganda ishlay boshlaydi" Faqat yakunlovchi iste'mol qilganda
"Generator quvuri bosqichma-bosqich ishlaydi" Elementma-element: har element butun quvurdan o'tadi
"groupby SQL GROUP BY kabi" Faqat yonma-yon elementlarni guruhlaydi
"tee xotira tejaydi" Orqada qolgan nusxa uchun elementlar saqlanadi
"sorted(generator) dangasa" Hammasini ro'yxatga yig'adi
"Generator doim ro'yxatdan tez" Kichik ma'lumotda ko'pincha sekinroq; foydasi — xotira va erta to'xtash
"Xato quvur qurilgan joyda chiqadi" Iste'mol qilingan joyda
"Eng katta N tani topish uchun saralash kerak" heapq.nlargest — O(N) xotira

6. Keng tarqalgan xatolar va yechimlari

1. Quvurni qurib, iste'mol qilmaslik

python
def saqla(oqim):
    for y in oqim:
        yield baza.yoz(y)           # ❌ generator — hech narsa yozilmaydi

saqla(yozuvlar)                     # ❌ natija tashlab yuborildi

def saqla(oqim):                    # ✅ yakunlovchi — oddiy funksiya
    for y in oqim:
        baza.yoz(y)

2. groupby dan oldin saralamaslik

python
groupby(sotuvlar, key=lambda s: s.mahsulot)                     # ❌
groupby(sorted(sotuvlar, key=lambda s: s.mahsulot), key=...)    # ✅

3. groupby guruhlarini keyin ishlatish

python
guruhlar = list(groupby(r, key))
for k, g in guruhlar: list(g)        # ❌ guruhlar bo'sh

{k: list(g) for k, g in groupby(r, key)}   # ✅

4. tee bilan ikki marta o'tish

python
a, b = tee(oqim)
ortacha = sum(a) / sum(1 for _ in b)        # ⚠️ butun oqim xotirada

jami = soni = 0                             # ✅ bitta o'tish
for x in oqim:
    jami += x; soni += 1

5. Quvur o'rtasida ro'yxatga aylantirish

python
qatorlar = [q for q in fayl]                # ⚠️ dangasalik yo'qoldi
xatolar = (q for q in qatorlar if "ERROR" in q)

xatolar = (q for q in fayl if "ERROR" in q) # ✅

6. Faylni generator ichida with siz ochish

python
def qatorlar(yol):
    f = open(yol)                           # ⚠️ quvur erta to'xtasa, qachon yopiladi?
    yield from f

def qatorlar(yol):
    with open(yol) as f:                    # ✅ generator yopilganda fayl ham yopiladi
        yield from f

7. Butun oqimni saralash uchun eng kattani topish

python
sorted(oqim, key=k, reverse=True)[:10]      # ⚠️ O(n) xotira, O(n log n)
heapq.nlargest(10, oqim, key=k)             # ✅ O(10) xotira

8. Buzuq qatorda butun quvurni to'xtatish

python
yozuvlar = (tahlil(q) for q in fayl)        # ❌ bitta buzuq qator — hammasi to'xtaydi

def xavfsiz(oqim, xatolar):                 # ✅ bosqich ichida ushlash
    for q in oqim:
        try: yield tahlil(q)
        except ValueError as e: xatolar.append((q, e))

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 10.1–10.3-darslar (o'tilgan): iterator protokoli va yield mexanizmi
  • 6.17-dars (o'tilgan): generator ifodalari
  • 9.8-dars (o'tilgan): xatolar strategiyasi — quvurdagi o'tkazib yuborish va ajratish
  • 10.5-dars: yield from — bosqichlarni bir-biriga ulash
  • 15-qism: itertools, heapq, collections to'liq
  • 16-qism: CSV, JSON Lines va katta fayllar bilan oqimli ishlash
  • 24-qism: pandas'dagi chunksize — xuddi shu g'oya jadvallar uchun

8. Eng yaxshi amaliyotlar

  1. Har bosqich bitta ish qilsin. O'qish, tozalash, tahlil, filtr — alohida generatorlar. Ular qayta ishlatiladi va alohida sinaladi.

  2. Yakunlovchi — oddiy funksiya. Yon ta'sirli ishni (yoz, yubor) generator qilmang, aks holda uni hech kim iste'mol qilmay qolishi mumkin.

  3. Resursni manba generatorida with bilan oching. Quvur erta to'xtasa ham yopiladi.

  4. groupby dan oldin saralang yoki lug'at ishlating.

  5. tee o'rniga bitta o'tishda hisoblang. Bir nechta natija kerak bo'lsa, hisoblagichlarni bitta siklda yuriting.

  6. Eng katta/kichik N ta — heapq. Butun oqimni saralamang.

  7. Buzuq yozuvlarni bosqich ichida ushlang va alohida yig'ing. Hisobotda nechta va qaysilar ekani ko'rinsin.

  8. Kichik ma'lumotda o'qilishini tanlang. Generator — xotira va erta to'xtash uchun, "chiroyli" ko'rinish uchun emas.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
from itertools import groupby, islice, takewhile, dropwhile, tee, pairwise, accumulate, chain, count
from collections import deque
1.  print([(k, len(list(g))) for k, g in groupby("aabccca")])
2.  print(list(takewhile(lambda x: x < 3, [1, 2, 5, 1])), list(dropwhile(lambda x: x < 3, [1, 2, 5, 1])))
3.  print(list(islice(count(10, 5), 3)))
4.  g = (x * x for x in range(5))
    print(list(islice(g, 2)), list(g))
5.  print(deque((x for x in range(10)), maxlen=1)[0])
6.  a, b = tee([1, 2, 3])
    print(list(a), list(b))
7.  print([b - a for a, b in pairwise([3, 8, 6])])
8.  print(list(accumulate([2, 5, 1, 7], max)))
9.  print(list(chain.from_iterable(["ab", [1, 2]])))
10. guruhlar = list(groupby("aab"))
    print([list(g) for _, g in guruhlar])
11. def bosqich(oqim):
        for x in oqim:
            print("b", x, end=" ")
            yield x * 10
    q = bosqich(iter([1, 2, 3]))
    print(next(q))
12. import heapq
    print(list(heapq.merge([1, 4, 9], [2, 3, 10])))
Javoblar
  1. [('a', 2), ('b', 1), ('c', 3), ('a', 1)] — oxirgi a alohida guruh
  2. [1, 2] [5, 1] — takewhile birinchi buzilishda to'xtaydi, dropwhile undan keyin hammasini beradi
  3. [10, 15, 20]
  4. [0, 1] [4, 9, 16] — islice generatordan ikkitasini oldi
  5. 9 — faqat oxirgisi saqlandi
  6. [1, 2, 3] [1, 2, 3]
  7. [5, -2]
  8. [2, 5, 5, 7]
  9. ['a', 'b', 1, 2]
  10. [[], []] — list() butun oqimni o'tib chiqdi, guruh iteratorlari yaroqsiz bo'ldi (eski versiyalarda oxirgi guruh ba'zan qolgan elementni berardi — bunga tayanmang)
  11. b 1 10 — faqat bitta element quvurdan o'tdi
  12. [1, 2, 3, 4, 9, 10]

Vazifa 2: Xatolarni tuzating

python
1.  def eksport(yozuvlar, fayl):
        for y in yozuvlar:
            yield fayl.write(f"{y}\n")
    eksport(barcha_yozuvlar, chiqish)

2.  from itertools import groupby
    for mahsulot, guruh in groupby(sotuvlar, key=lambda s: s["mahsulot"]):
        print(mahsulot, sum(s["summa"] for s in guruh))

3.  from itertools import tee
    a, b = tee(katta_log_oqimi)
    xatolar = sum(1 for q in a if "ERROR" in q)
    ogohlar = sum(1 for q in b if "WARN" in q)

4.  top10 = sorted(juda_katta_oqim, key=lambda y: y.ball, reverse=True)[:10]

5.  def qatorlar(yol):
        f = open(yol)
        for q in f:
            yield q
Javoblar
python
1.  def eksport(yozuvlar, fayl):            # generator emas — yakunlovchi
        for y in yozuvlar:
            fayl.write(f"{y}\n")

2.  sotuvlar = sorted(sotuvlar, key=lambda s: s["mahsulot"])   # avval saralash
    # yoki: defaultdict(int) bilan saralashsiz yig'ish

3.  xatolar = ogohlar = 0                   # bitta o'tish, tee siz
    for q in katta_log_oqimi:
        xatolar += "ERROR" in q
        ogohlar += "WARN" in q

4.  import heapq
    top10 = heapq.nlargest(10, juda_katta_oqim, key=lambda y: y.ball)

5.  def qatorlar(yol):
        with open(yol) as f:
            yield from f

Vazifa 3: Log tahlilchi quvuri

Veb-server logi (sana vaqt metod yo'l kod ms) uchun quvur yozing:

  1. qatorlar(yol) — manba, with bilan
  2. tahlil(oqim, xatolar) — buzuq qatorlarni xatolar ga yig'sin
  3. vaqt_oraligi(oqim, bosh, oxir) — dropwhile + takewhile bilan (log sana bo'yicha saralangan)
  4. eng_sekin(oqim, n) — heapq.nlargest
  5. 5 000 000 qatorli sun'iy log bilan xotira 20 MB dan oshmasligini tracemalloc bilan tekshiring

Vazifa 4: Retseptlarni kengaytiring

Misol 3 ga qo'shing va har biriga sinov yozing:

  1. birinchi_n_takrorsiz(oqim, n) — n ta noyob element topilgach to'xtasin
  2. bolaklab_vaqt(oqim, kalit, soniya) — vaqt oynasi bo'yicha guruhlash (masalan, har 60 soniya)
  3. aralash_nlargest(oqimlar, n, key) — bir nechta oqimdan eng katta n ta
  4. tekislash(ichma_ich, chuqurlik) — berilgan chuqurlikkacha tekislash (satrlarni harflarga bo'lmasin)

Vazifa 5: tee siz statistika

Generatorni bir marta aylanib, quyidagilarni hisoblaydigan statistika(oqim) yozing: soni, jami, o'rtacha, min, max, dispersiya va medianga yaqin qiymat (maslahat: P² algoritmi yoki heapq bilan ikki uyum). tee bilan yozilgan variant bilan xotirani solishtiring.

Vazifa 6: Oqimli birlashtirish (join)

Ikki katta CSV oqimi bor: buyurtmalar (mijoz_id bo'yicha saralangan) va mijozlar (id bo'yicha saralangan). Ularni ikkalasini ham xotiraga yuklamasdan birlashtiradigan birlashtir(buyurtmalar, mijozlar) generatorini yozing (merge join). Mijozi topilmagan buyurtmalarni alohida ro'yxatga yig'ing.

Vazifa 7: O'ylash

Generator quvuri Unix'dagi cat log | grep 500 | sort | head -10 ga o'xshatiladi. Ular qaysi jihatlarda haqiqatan o'xshash va qaysi jihatlarda tubdan farq qiladi? Nega bu quvurdagi sort ikkala dunyoda ham muammoli?

Javob

Qisqa javob: ikkalasi ham "kichik bosqichlarni ulash" va "ma'lumotni oqim sifatida uzatish" g'oyasiga asoslangan. Farqi — Unix'da bosqichlar alohida jarayonlar va ma'lumot baytlar sifatida parallel oqadi; Python generatorlarida esa bosqichlar bitta jarayondagi funksiyalar, ma'lumot obyektlar sifatida navbat bilan (tortib olish orqali) uzatiladi. sort esa ikkalasida ham butun oqimni ko'rmasdan ishlay olmaydi.

1. O'xshashliklar

Jihat Unix quvuri Generator quvuri
Bosqich Bitta ish qiladigan dastur Bitta ish qiladigan generator
Ulash a | b | c c(b(a()))
Oqim Qatorma-qator Elementma-element
Xotira Bufer hajmida Bitta element
Erta to'xtash head yopilsa, oldingilar SIGPIPE oladi Yakunlovchi to'xtasa, generatorlar to'xtab qoladi

Ikkalasida ham "kichik, bir ishni yaxshi bajaradigan qismlar" falsafasi (Unix falsafasi) ishlaydi.

2. Tub farqlar

a) Bir vaqtda ishlash.

Unix'da cat, grep, sort, head — to'rtta alohida jarayon va ular bir vaqtda ishlaydi. cat o'qiyotganda grep allaqachon filtrlayapti — ko'p yadroli protsessordan foydalanadi.

Generator quvuri esa bitta ipda ishlaydi: yakunlovchi next() so'raydi, bu so'rov zanjir bo'ylab manbagacha boradi, bitta element qaytadi. Hech qachon ikki bosqich bir vaqtda ishlamaydi.

b) Itarish va tortish (push vs pull).

  • Unix — itarish: cat imkoni boricha tez yozadi, bufer to'lsa (odatda 64 KB) kutadi
  • Generator — tortish: hech kim so'ramasa, manba hech narsa qilmaydi

Shuning uchun generatorda "orqaga bosim" (backpressure) muammosi umuman yo'q — tez manba sekin iste'molchini "bosib ketolmaydi".

c) Ma'lumot turi.

Unix quvurida faqat baytlar oqadi. Har bosqich matnni qayta tahlil qiladi — sana, raqam, ustunlar har safar satrdan qayta ajratiladi.

Generatorda obyektlar oqadi: bir marta tahlil qilingan Sotuv obyekti keyingi bosqichlarga tayyor holda uzatiladi. Bu tezroq va xatolarga kamroq moyil.

d) Xatolar.

Unix'da bosqich yiqilsa, qolganlari ko'pincha davom etadi va $? faqat oxirgisining kodini beradi (set -o pipefail bo'lmasa). Xato jimgina yo'qolishi mumkin.

Generatorda xato istisno bo'lib yakunlovchigacha ko'tariladi — traceback butun zanjirni ko'rsatadi.

e) Resurslar.

Unix jarayonlari xotirani izolyatsiya qiladi. Generatorlar bitta jarayon xotirasini bo'lishadi — bosqichlar orasida katta obyektlarni nusxalamasdan uzatish mumkin.

3. Nega sort ikkalasida ham muammo

sort birinchi qatorni chiqarishdan oldin eng kichik qator qaysi ekanini bilishi kerak — buning uchun esa hamma qatorlarni ko'rishi shart. Bu matematik zaruriyat: istalgan saralash algoritmi oxirgi elementni ko'rmaguncha birinchi o'rinni kafolatlay olmaydi.

Oqibatlar:

  • head -10 10 ta qatordan keyin to'xtaydi, lekin sort baribir butun faylni o'qib bo'lgan
  • Erta to'xtash foydasi yo'qoladi
  • Xotira: GNU sort katta faylni vaqtinchalik fayllarga bo'lib, tashqi saralash qiladi; Python'dagi sorted() esa hammasini operativ xotiraga yig'adi

4. Yechimlar

a) Aslida saralash kerak emas — faqat eng yaxshi N ta.

bash
sort -k6 -n log | tail -10           # butun oqim saralanadi
python
heapq.nlargest(10, oqim, key=...)    # O(n log 10) vaqt, O(10) xotira

Ko'p "saralash" vazifalari aslida "top-N" vazifasi. Python'da heapq.nlargest buni bitta o'tishda qiladi.

b) Manba allaqachon saralangan.

Loglar vaqt bo'yicha yoziladi. Bir nechta saralangan oqimni birlashtirish uchun saralash emas, heapq.merge kerak (Misol 4) — u ham to'liq dangasa.

c) Guruhlash uchun saralash.

sort | uniq -c va sorted + groupby o'rniga collections.Counter yoki defaultdict — xotira noyob kalitlar soniga bog'liq bo'ladi, oqim uzunligiga emas.

d) Haqiqatan to'liq saralash kerak bo'lsa — tashqi saralash: oqimni bo'laklab, har bo'lakni saralab, vaqtinchalik fayllarga yozish va heapq.merge bilan birlashtirish. GNU sort aynan shunday ishlaydi.

5. Python'da haqiqiy parallel quvur

Bosqichlar og'ir hisoblash qilsa va parallellik kerak bo'lsa, generatorlar yetmaydi. Unda:

  • concurrent.futures + navbatlar (14-qism)
  • multiprocessing bilan jarayonlar quvuri
  • asinxron generatorlar (async for) — I/O kutish uchun

Lekin bu murakkablik qo'shadi. Ko'p amaliy vazifalarda asosiy tor joy xotira bo'ladi, parallellik emas. Oddiy generator quvuri esa aynan xotira muammosini hal qiladi.

6. Xulosa

  1. O'xshash: kichik bosqichlar, oqim sifatida uzatish, erta to'xtash
  2. Farq: Unix — parallel jarayonlar, baytlar, itarish; generator — bitta ip, obyektlar, tortish
  3. Tortish modeli orqaga bosim muammosini yo'q qiladi, lekin ko'p yadrodan foydalanmaydi
  4. sort ikkalasida ham butun oqimni ko'rishi shart — bu algoritmik zaruriyat
  5. Ko'pincha saralash o'rniga heapq.nlargest, heapq.merge yoki Counter yetadi

Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.


Xulosa

Bu darsda generatorlarni real vazifalarda ishlatishni o'rgandik.

Eng muhim uch fikr:

  1. Generator quvuri — manba, oraliq bosqichlar va yakunlovchi. Quvur qurilganda hech narsa bajarilmaydi, yakunlovchi elementlarni tortib ola boshlaganda esa har element butun zanjirdan birma-bir o'tadi. Shuning uchun xotirada bir vaqtda bitta element turadi va yakunlovchi to'xtasa, manba ham o'qishni to'xtatadi. Yon ta'sirli ishni generator emas, oddiy yakunlovchi funksiya bajarsin.

  2. itertools va heapq — tayyor quvur bosqichlari, lekin ikki tuzoq bor. islice, takewhile, chain.from_iterable, pairwise, batched, heapq.merge va heapq.nlargest quvurni to'liq dangasa saqlaydi. groupby faqat yonma-yon elementlarni guruhlaydi va guruhlarini darhol iste'mol qilishni talab qiladi; tee esa orqada qolgan nusxa uchun elementlarni xotirada saqlaydi — ko'pincha bitta o'tishda hisoblash yaxshiroq.

  3. Dangasalik xatolarni kechiktiradi — ularni bosqich ichida boshqaring. Buzuq yozuvni o'sha bosqichda ushlab, alohida ro'yxatga yig'ish butun quvurni to'xtatmaydi va hisobotda nechta xato bo'lganini ko'rsatadi. Ma'lumot kichik bo'lsa esa ro'yxat soddaroq: generator xotira va erta to'xtash uchun kerak.

Keyingi darsda yield from bilan tanishamiz: bir generator ishni boshqasiga qanday topshiradi, qaytish qiymati qanday olinadi va send()/throw() zanjir bo'ylab qanday uzatiladi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
10.4-dars: Generator amaliyoti — IlmHamroh