IlmHamroh
Python kursi/Standart kutubxona8/16-dars23 daqiqa
Mundarija (22)

15.8-dars: itertools: asosiy

15-QISM — STANDART KUTUBXONA · 8-dars


1. Kirish va motivatsiya

9-qismda iterator va generatorlarni o'rgandik: ular elementlarni bittadan, so'ralganda beradi. itertools moduli shu g'oyaning "asboblar qutisi": iteratorlarni kesish, birlashtirish, guruhlash, yig'ish va paketlash uchun C da yozilgan tez va dangasa qurilmalar.

Real vaziyat. Jamoa kunlik jurnal faylini (12 GB) tahlil qilardi:

python
qatorlar = open(yol).readlines()          # butun fayl xotiraga
xatolar = [q for q in qatorlar if "ERROR" in q]
birinchi_100 = xatolar[:100]

Server 8 GB xotiraga ega edi — skript MemoryError bilan yiqildi. Xuddi shu vazifa dangasa quvur bilan bir necha megabayt xotirada ishlaydi:

python
with open(yol) as f:
    xatolar = (q for q in f if "ERROR" in q)
    birinchi_100 = list(itertools.islice(xatolar, 100))   # 100 ta topilgach — to'xtaydi

Lekin dangasalikning o'z tuzoqlari bor: iterator bir marta o'qiladi, groupby saralanmagan ma'lumotda "noto'g'ri" guruhlaydi, in tekshiruvi elementlarni iste'mol qiladi. Bu darsda ikkalasini ham ko'ramiz.

Bu darsda:

  • Dangasalik va bir martalik iteratorlar
  • Cheksiz iteratorlar: count, cycle, repeat
  • islice — iteratorni kesish
  • chain, zip_longest, pairwise, batched
  • Filtrlash: takewhile, dropwhile, filterfalse, compress
  • accumulate — yig'ilib boruvchi natijalar
  • groupby — faqat ketma-ket kelganlar
  • tee — iteratorni ikkiga bo'lish va uning narxi
  • Amaliy: millionlab qatorli jurnalni oqim bilan qayta ishlash

2. Nazariya — chuqur tushuntirish

2.1. Dangasalik va bir martalik iteratorlar

itertools funksiyalari iterator qaytaradi: hech narsa hisoblamaydi, faqat next() so'ralganda bitta element beradi.

Obyekt Qayta o'qish mumkinmi
list, tuple, range, str Har safar yangi iterator
Generator, map, filter, zip Bir marta
itertools.* natijalari Bir marta
Ochilgan fayl Bir marta (oxirigacha o'qilgach)
python
g = (x for x in range(3))
list(g)     # [0, 1, 2]
list(g)     # []  — jim bo'sh

in ham iteratorni iste'mol qiladi:

python
it = iter([1, 2, 3, 4])
2 in it     # True — lekin 1 va 2 o'qib bo'lindi
list(it)    # [3, 4]
Afzallik Narxi
Xotira — O(1) Qayta o'qib bo'lmaydi
Cheksiz ketma-ketliklar len(), indeks, kesma yo'q
Erta to'xtash Xato kechroq ko'rinadi (dangasa)

2.2. Cheksiz iteratorlar

Funksiya Natija
count(boshi=0, qadam=1) 0, 1, 2, ...
cycle(it) a, b, a, b, ...
repeat(x, n=None) x, x, x, ... (yoki n marta)

Cheksiz iteratorni list() ga bermang — xotira tugaguncha ishlaydi. Doim islice, zip yoki takewhile bilan chegaralang.

2.3. islice

python
islice(it, stop)
islice(it, start, stop, step)
Xususiyat seq[a:b:c] islice(it, a, b, c)
Istalgan iterable Faqat ketma-ketlik
Manfiy indeks ValueError
Xotira Nusxa yaratadi Dangasa
Boshlanishgacha To'g'ridan-to'g'ri start gacha elementlar o'qib tashlanadi

2.4. Birlashtirish va paketlash

Funksiya Natija
chain(a, b) a elementlari, keyin b
chain.from_iterable(ichma_ich) Bir daraja tekislash — dangasa
zip(a, b, strict=True) Uzunliklar teng bo'lmasa ValueError (3.10+)
zip_longest(a, b, fillvalue=x) Eng uzunigacha, bo'sh joylar x
pairwise(it) (a0, a1), (a1, a2), ... (3.10+)
batched(it, n) n talik kortejlar, oxirgisi qisqa bo'lishi mumkin (3.12+)
batched(it, n, strict=True) Oxirgisi to'liq bo'lmasa ValueError (3.13+)
starmap(f, juftlar) f(*juft)

batched — bazaga paketlab yozish, API ga bo'lib yuborishning standart vositasi.

2.5. Filtrlash

Funksiya Qachon to'xtaydi / nima qiladi
filter(shart, it) Shart bajarilganlarini beradi
filterfalse(shart, it) Shart bajarilmaganlarini
takewhile(shart, it) Shart birinchi marta bajarilmaguncha — keyin to'xtaydi
dropwhile(shart, it) Shart bajarilguncha tashlaydi, keyin hammasini beradi
compress(it, belgilar) belgilar[i] rost bo'lganlarini
python
list(takewhile(lambda x: x < 3, [1, 2, 5, 1]))   # [1, 2]  — oxirgi 1 kelmaydi
list(dropwhile(lambda x: x < 3, [1, 2, 5, 1]))   # [5, 1]  — 1 ham qaytadi

takewhile shart bajarilmagan birinchi elementni ham iste'mol qiladi — u yo'qoladi.

2.6. accumulate

python
accumulate([1, 2, 3, 4])                 # 1, 3, 6, 10    — yig'indi
accumulate([1, 2, 3, 4], operator.mul)   # 1, 2, 6, 24    — ko'paytma
accumulate([3, 1, 4, 1, 5], max)         # 3, 3, 4, 4, 5  — shu paytgacha maksimum
accumulate([1, 2, 3], initial=100)       # 100, 101, 103, 106

Qo'llanishlar: kumulyativ tushum, hisob qoldig'i, "rekord" qiymatlar, prefiks yig'indilar (oraliq yig'indisini O(1) da hisoblash).

2.7. groupby

groupby(it, key) — ketma-ket kelgan bir xil kalitli elementlarni guruhlaydi. U SQL GROUP BY emas.

python
sozlar = ["olma", "anor", "olcha"]
[(k, list(g)) for k, g in groupby(sozlar, key=lambda s: s[0])]
# [('o', ['olma']), ('a', ['anor']), ('o', ['olcha'])]   — 'o' ikki marta!

[(k, list(g)) for k, g in groupby(sorted(sozlar), key=lambda s: s[0])]
# [('a', ['anor']), ('o', ['olcha', 'olma'])]
Tuzoq Yechim
Ma'lumot saralanmagan Avval sorted(..., key=bir_xil_kalit) yoki defaultdict(list) (15.6)
Guruhlar keyinroq o'qiladi list(groupby(...)) — guruhlar bo'shab qoladi; har guruhni darhol list(g) qiling
Saralash kaliti ≠ guruhlash kaliti Bir xil kalit funksiyasi
Vosita Xotira Saralash kerakmi Qachon
groupby O(1) (bitta guruh) Oqim allaqachon tartiblangan (vaqt, fayl)
defaultdict(list) O(n) Tartibsiz ma'lumot

2.8. tee

tee(it, n=2) — bitta iteratordan n ta mustaqil iterator.

Narxi: bir nusxa oldinda ketsa, ikkinchisi uchun o'qilgan elementlar buferda saqlanadi. Biri oxirigacha o'qilsa — hammasi xotirada. tee dan keyin asl iteratorni ishlatmang.

Ikki marta o'qish kerak va ma'lumot kichik bo'lsa — list oddiyroq va tezroq.


3. Tez ma'lumotnoma

python
import itertools as it
import operator

it.islice(oqim, 100)                          # birinchi 100 ta
it.chain.from_iterable(royxatlar)             # tekislash
it.batched(yozuvlar, 1000)                    # 1000 talik paketlar
it.pairwise(vaqtlar)                          # qo'shni juftliklar
it.accumulate(summalar)                       # kumulyativ yig'indi
for kalit, guruh in it.groupby(sorted(xs, key=f), key=f):
    elementlar = list(guruh)                  # darhol
it.takewhile(lambda q: q.startswith("#"), qatorlar)

Qoidalar

iterator bir martalik — kerak bo'lsa list()
in ham iteratorni iste'mol qiladi
cheksiz iterator — doim chegara bilan
groupby — faqat ketma-ket; avval sorted
groupby guruhini darhol o'qing
tee — faqat yaqin yurgan nusxalar uchun

4. Batafsil misollar

Misol 1 — Dangasalik va bir martalik iteratorlar

python
"""Generator, zip, map bir martalik; in iste'mol qiladi; range qayta o'qiladi; dangasa quvur tartibi; cheksiz iteratorlar; xotira."""

import itertools as it
import sys


def main() -> None:
    print("=== 1. ⚠️ Bir martalik ===")
    g = (x * x for x in range(4))
    print(f"  generator: {list(g)}, qayta: {list(g)}")
    z = zip("ab", [1, 2])
    print(f"  zip:       {list(z)}, qayta: {list(z)}")
    r = range(3)
    print(f"  range:     {list(r)}, qayta: {list(r)}")

    print("\n=== 2. ⚠️ in iteratorni iste'mol qiladi ===")
    raqamlar = iter([1, 2, 3, 4, 5])
    print(f"  3 in raqamlar: {3 in raqamlar}")
    print(f"  qolgani: {list(raqamlar)}")
    sonlar = map(int, "12345")
    print(f"  sum(map) = {sum(sonlar)}, keyin max(default=None): {max(sonlar, default=None)}")

    print("\n=== 3. Dangasa quvur: nima qachon bajariladi ===")
    jurnal: list[str] = []

    def manba():
        for i in range(1, 6):
            jurnal.append(f"o'qildi {i}")
            yield i

    juftlar = (x for x in manba() if x % 2 == 0)
    kvadratlar = (x * x for x in juftlar)
    print(f"  quvur qurildi, jurnal: {jurnal}")
    birinchisi = next(kvadratlar)
    print(f"  next() = {birinchisi}, jurnal: {jurnal}")
    print("  ⭐ faqat birinchi natija uchun kerak bo'lgan elementlar o'qildi")

    print("\n=== 4. Cheksiz iteratorlar ===")
    print(f"  count(10, 5):   {list(it.islice(it.count(10, 5), 4))}")
    print(f"  cycle('KQS'):   {''.join(it.islice(it.cycle('KQS'), 7))}")
    print(f"  repeat('-', 5): {''.join(it.repeat('-', 5))}")
    navbatchilar = ["Aziz", "Malika", "Bek"]
    kunlar = ["du", "se", "chor", "pay", "ju"]
    print(f"  navbatchilik: {list(zip(kunlar, it.cycle(navbatchilar)))}")

    print("\n=== 5. Xotira ===")
    royxat = list(range(1_000_000))
    dangasa = it.islice(it.count(), 1_000_000)
    print(f"  1 mln elementli list: {sys.getsizeof(royxat) // 1024} KB")
    print(f"  islice(count()):      {sys.getsizeof(dangasa)} bayt")
    print(f"  natijalar yig'indisi teng: {sum(royxat) == sum(dangasa)}")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. ⚠️ Bir martalik ===
  generator: [0, 1, 4, 9], qayta: []
  zip:       [('a', 1), ('b', 2)], qayta: []
  range:     [0, 1, 2], qayta: [0, 1, 2]

=== 2. ⚠️ in iteratorni iste'mol qiladi ===
  3 in raqamlar: True
  qolgani: [4, 5]
  sum(map) = 15, keyin max(default=None): None

=== 3. Dangasa quvur: nima qachon bajariladi ===
  quvur qurildi, jurnal: []
  next() = 4, jurnal: ["o'qildi 1", "o'qildi 2"]
  ⭐ faqat birinchi natija uchun kerak bo'lgan elementlar o'qildi

=== 4. Cheksiz iteratorlar ===
  count(10, 5):   [10, 15, 20, 25]
  cycle('KQS'):   KQSKQSK
  repeat('-', 5): -----
  navbatchilik: [('du', 'Aziz'), ('se', 'Malika'), ('chor', 'Bek'), ('pay', 'Aziz'), ('ju', 'Malika')]

=== 5. Xotira ===
  1 mln elementli list: 7812 KB
  islice(count()):      72 bayt
  natijalar yig'indisi teng: True

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

Misol 2 — Kesish, birlashtirish va filtrlash

python
"""islice va uning cheklovlari; chain va from_iterable; zip strict va zip_longest; pairwise; batched va strict; takewhile, dropwhile, filterfalse, compress."""

import itertools as it


def main() -> None:
    print("=== 1. islice ===")
    print(f"  islice(range(10), 2, 8, 3): {list(it.islice(range(10), 2, 8, 3))}")
    print(f"  fayl kabi oqimdan 3 ta:     {list(it.islice(iter(['a', 'b', 'c', 'd']), 3))}")
    try:
        it.islice(range(10), -3, None)
    except ValueError:
        print("  islice(..., -3) → ValueError: manfiy indeks yo'q")

    print("\n=== 2. chain ===")
    guruhlar = [["Aziz", "Bek"], ["Malika"], [], ["Nodira", "Sardor"]]
    print(f"  chain(*guruhlar):             {list(it.chain(*guruhlar))}")
    print(f"  chain.from_iterable(guruhlar): {list(it.chain.from_iterable(guruhlar))}")

    print("\n=== 3. zip, zip_longest ===")
    ismlar, ballar = ["Aziz", "Bek", "Malika"], [87, 92]
    print(f"  zip:          {list(zip(ismlar, ballar))}  ← Malika jim yo'qoldi")
    try:
        list(zip(ismlar, ballar, strict=True))
    except ValueError as xato:
        print(f"  strict=True:  ValueError: {xato}")
    print(f"  zip_longest:  {list(it.zip_longest(ismlar, ballar, fillvalue=None))}")

    print("\n=== 4. pairwise ===")
    narxlar = [12_000, 12_500, 12_100, 13_000, 13_000]
    ozgarish = [b - a for a, b in it.pairwise(narxlar)]
    print(f"  narxlar: {narxlar}")
    print(f"  kunlik o'zgarish: {ozgarish}")

    print("\n=== 5. batched ===")
    print(f"  batched(range(7), 3): {list(it.batched(range(7), 3))}")
    try:
        list(it.batched(range(7), 3, strict=True))
    except ValueError as xato:
        print(f"  strict=True: ValueError: {xato}")

    print("\n=== 6. Filtrlash ===")
    fayl = ["# sozlamalar", "# muallif: Wisar", "host=localhost", "# izoh", "port=5432"]
    print(f"  takewhile (sarlavha): {list(it.takewhile(lambda q: q.startswith('#'), fayl))}")
    print(f"  dropwhile (qolgani):  {list(it.dropwhile(lambda q: q.startswith('#'), fayl))}")
    print(f"  filterfalse (izohsiz): {list(it.filterfalse(lambda q: q.startswith('#'), fayl))}")
    print(f"  compress:  {list(it.compress(['du', 'se', 'chor', 'pay', 'ju'], [1, 0, 1, 0, 1]))}")

    print("\n=== 7. ⚠️ takewhile bitta elementni yutadi ===")
    oqim = iter([1, 2, 5, 3, 4])
    kichiklar = list(it.takewhile(lambda x: x < 3, oqim))
    print(f"  takewhile: {kichiklar}, oqimda qolgani: {list(oqim)}  ← 5 yo'qoldi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. islice ===
  islice(range(10), 2, 8, 3): [2, 5]
  fayl kabi oqimdan 3 ta:     ['a', 'b', 'c']
  islice(..., -3) → ValueError: manfiy indeks yo'q

=== 2. chain ===
  chain(*guruhlar):             ['Aziz', 'Bek', 'Malika', 'Nodira', 'Sardor']
  chain.from_iterable(guruhlar): ['Aziz', 'Bek', 'Malika', 'Nodira', 'Sardor']

=== 3. zip, zip_longest ===
  zip:          [('Aziz', 87), ('Bek', 92)]  ← Malika jim yo'qoldi
  strict=True:  ValueError: zip() argument 2 is shorter than argument 1
  zip_longest:  [('Aziz', 87), ('Bek', 92), ('Malika', None)]

=== 4. pairwise ===
  narxlar: [12000, 12500, 12100, 13000, 13000]
  kunlik o'zgarish: [500, -400, 900, 0]

=== 5. batched ===
  batched(range(7), 3): [(0, 1, 2), (3, 4, 5), (6,)]
  strict=True: ValueError: batched(): incomplete batch

=== 6. Filtrlash ===
  takewhile (sarlavha): ['# sozlamalar', '# muallif: Wisar']
  dropwhile (qolgani):  ['host=localhost', '# izoh', 'port=5432']
  filterfalse (izohsiz): ['host=localhost', 'port=5432']
  compress:  ['du', 'chor', 'ju']

=== 7. ⚠️ takewhile bitta elementni yutadi ===
  takewhile: [1, 2], oqimda qolgani: [3, 4]  ← 5 yo'qoldi

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

Misol 3 — accumulate, groupby, tee

python
"""accumulate: yig'indi, maksimum, initial, prefiks yig'indilar; groupby: saralanmagan tuzog'i, guruhlarni kech o'qish tuzog'i, defaultdict bilan solishtirish; tee buferi."""

import itertools as it
import operator
from collections import defaultdict


def main() -> None:
    print("=== 1. accumulate ===")
    tushum = [120, 80, 150, 90, 200]
    print(f"  kunlik:         {tushum}")
    print(f"  kumulyativ:     {list(it.accumulate(tushum))}")
    print(f"  rekordlar:      {list(it.accumulate(tushum, max))}")
    print(f"  ko'paytma:      {list(it.accumulate([1, 2, 3, 4], operator.mul))}")
    print(f"  boshlang'ich 500: {list(it.accumulate([-120, 300, -50], initial=500))}")

    prefiks = list(it.accumulate(tushum, initial=0))
    print(f"  prefiks yig'indi: {prefiks}")
    print(f"  2..4-kunlar yig'indisi O(1): {prefiks[5] - prefiks[1]} (tekshiruv: {sum(tushum[1:5])})")

    print("\n=== 2. ⚠️ groupby saralanmagan ma'lumotda ===")
    mevalar = ["olma", "anor", "banan", "behi", "olcha", "avakado"]
    birinchi_harf = operator.itemgetter(0)
    xato = [(k, list(g)) for k, g in it.groupby(mevalar, key=birinchi_harf)]
    togri = [(k, list(g)) for k, g in it.groupby(sorted(mevalar, key=birinchi_harf), key=birinchi_harf)]
    print(f"  saralanmagan: {xato}")
    print(f"  saralangan:   {togri}")

    print("\n=== 3. ⚠️ Guruhni kech o'qish ===")
    guruhlar = list(it.groupby("aaabbc"))
    print(f"  list(groupby(...)) keyin: {[(k, list(g)) for k, g in guruhlar]}  ← guruhlar bo'sh")
    darhol = [(k, len(list(g))) for k, g in it.groupby("aaabbc")]
    print(f"  darhol o'qilganda:       {darhol}")

    print("\n=== 4. Ketma-ketliklarni siqish (run-length) ===")
    signal = "AAAABBBCCDAA"
    siqilgan = "".join(f"{k}{len(list(g))}" for k, g in it.groupby(signal))
    print(f"  {signal} → {siqilgan}")
    print("  ⭐ bu yerda aynan ketma-ketlik kerak — saralash xato bo'lardi")

    print("\n=== 5. groupby va defaultdict ===")
    buyurtmalar = [("2026-09-15", 120), ("2026-09-15", 80), ("2026-09-16", 200), ("2026-09-15", 50)]
    oqim_boyicha = {k: sum(s for _, s in g) for k, g in it.groupby(buyurtmalar, key=operator.itemgetter(0))}
    lugat: defaultdict[str, int] = defaultdict(int)
    for kun, summa in buyurtmalar:
        lugat[kun] += summa
    print(f"  groupby (saralanmagan): {oqim_boyicha}  ← 15-sentabr qayta yozildi")
    print(f"  defaultdict:            {dict(lugat)}")

    print("\n=== 6. tee ===")
    a, b = it.tee(iter([1, 2, 3]))
    print(f"  a: {list(a)}, b: {list(b)}")
    oldingi, keyingi = it.tee(iter(range(5)))
    next(keyingi, None)
    qolda = list(zip(oldingi, keyingi))
    print(f"  qo'lda pairwise: {qolda}")
    print(f"  itertools.pairwise bilan bir xil: {qolda == list(it.pairwise(range(5)))}")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. accumulate ===
  kunlik:         [120, 80, 150, 90, 200]
  kumulyativ:     [120, 200, 350, 440, 640]
  rekordlar:      [120, 120, 150, 150, 200]
  ko'paytma:      [1, 2, 6, 24]
  boshlang'ich 500: [500, 380, 680, 630]
  prefiks yig'indi: [0, 120, 200, 350, 440, 640]
  2..4-kunlar yig'indisi O(1): 520 (tekshiruv: 520)

=== 2. ⚠️ groupby saralanmagan ma'lumotda ===
  saralanmagan: [('o', ['olma']), ('a', ['anor']), ('b', ['banan', 'behi']), ('o', ['olcha']), ('a', ['avakado'])]
  saralangan:   [('a', ['anor', 'avakado']), ('b', ['banan', 'behi']), ('o', ['olma', 'olcha'])]

=== 3. ⚠️ Guruhni kech o'qish ===
  list(groupby(...)) keyin: [('a', []), ('b', []), ('c', [])]  ← guruhlar bo'sh
  darhol o'qilganda:       [('a', 3), ('b', 2), ('c', 1)]

=== 4. Ketma-ketliklarni siqish (run-length) ===
  AAAABBBCCDAA → A4B3C2D1A2
  ⭐ bu yerda aynan ketma-ketlik kerak — saralash xato bo'lardi

=== 5. groupby va defaultdict ===
  groupby (saralanmagan): {'2026-09-15': 50, '2026-09-16': 200}  ← 15-sentabr qayta yozildi
  defaultdict:            {'2026-09-15': 250, '2026-09-16': 200}

=== 6. tee ===
  a: [1, 2, 3], b: [1, 2, 3]
  qo'lda pairwise: [(0, 1), (1, 2), (2, 3), (3, 4)]
  itertools.pairwise bilan bir xil: True

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

Misol 4 — Amaliy: millionlab qatorli jurnalni oqim bilan qayta ishlash

Kirishdagi vaziyat: katta jurnal faylini xotiraga yuklamasdan qayta ishlaymiz. Jurnal generator bilan hosil qilinadi (1 000 000 qator — faylni o'qishning o'zi kabi dangasa). Quvur: ERROR qatorlarni ajratish, birinchi 3 tasini ko'rish, daqiqalar bo'yicha guruhlash (jurnal vaqt bo'yicha tartiblangan — groupby ideal), xatolar orasidagi eng uzun tanaffus (pairwise), bazaga 50 000 talik paketlar (batched). Oxirida xotira sarfini tracemalloc bilan ro'yxat usuli bilan solishtiramiz.

python
"""Dangasa quvur: generator manba, filter, islice, groupby, pairwise, batched, accumulate; tracemalloc bilan xotira solishtiruvi."""

import itertools as it
import tracemalloc
from collections.abc import Iterator

QATORLAR = 1_000_000


def jurnal() -> Iterator[str]:
    """Faylni satrma-satr o'qishni taqlid qiladi: har 1 soniyada bitta yozuv."""
    for i in range(QATORLAR):
        kun, qoldiq = divmod(i, 86_400)
        soat, qoldiq = divmod(qoldiq, 3600)
        daqiqa, soniya = divmod(qoldiq, 60)
        daraja = "ERROR" if (i % 997 == 0 or 500_000 <= i < 500_020) else "INFO"
        yield f"2026-09-{17 + kun:02d}T{soat:02d}:{daqiqa:02d}:{soniya:02d} {daraja} so'rov={i}"


def soniya(qator: str) -> int:
    kun = int(qator[8:10]) - 17
    s, d, c = qator[11:19].split(":")
    return kun * 86_400 + int(s) * 3600 + int(d) * 60 + int(c)


def xatolar(qatorlar: Iterator[str]) -> Iterator[str]:
    return (q for q in qatorlar if " ERROR " in q)


def quvur() -> dict[str, object]:
    natija: dict[str, object] = {}
    natija["birinchi_3"] = [q.split()[-1] for q in it.islice(xatolar(jurnal()), 3)]

    daqiqalar = it.groupby(xatolar(jurnal()), key=lambda q: q[:16])
    zich = max(((kalit, sum(1 for _ in guruh)) for kalit, guruh in daqiqalar), key=lambda kg: kg[1])
    natija["eng_zich_daqiqa"] = zich

    vaqtlar = (soniya(q) for q in xatolar(jurnal()))
    tanaffus = max(b - a for a, b in it.pairwise(vaqtlar))
    natija["eng_uzun_tanaffus_s"] = tanaffus

    paketlar = it.batched(xatolar(jurnal()), 500)
    hajmlar = [len(p) for p in paketlar]
    natija["paketlar"] = (len(hajmlar), hajmlar[-1])
    natija["jami_xato"] = list(it.accumulate(hajmlar))[-1]
    return natija


def royxat_usuli() -> int:
    qatorlar = list(jurnal())
    return len([q for q in qatorlar if " ERROR " in q])


def main() -> None:
    tracemalloc.start()
    natija = quvur()
    _, quvur_cho_qqisi = tracemalloc.get_traced_memory()
    tracemalloc.reset_peak()
    royxat_natija = royxat_usuli()
    _, royxat_cho_qqisi = tracemalloc.get_traced_memory()
    tracemalloc.stop()

    print(f"=== 1. {QATORLAR:_} qatorli jurnal ===".replace("_", " "))
    print(f"  birinchi 3 xato: {natija['birinchi_3']}")
    print(f"  eng zich daqiqa: {natija['eng_zich_daqiqa']}")
    print(f"  xatolar orasidagi eng uzun tanaffus: {natija['eng_uzun_tanaffus_s']} s")
    print(f"  500 talik paketlar: {natija['paketlar'][0]} ta, oxirgisi {natija['paketlar'][1]} ta yozuv")
    print(f"  jami xato: {natija['jami_xato']}")

    print("\n=== 2. Tekshiruvlar ===")
    print(f"  ro'yxat usuli bilan bir xil son: {natija['jami_xato'] == royxat_natija}")
    kutilgan = len({i for i in range(QATORLAR) if i % 997 == 0} | set(range(500_000, 500_020)))
    print(f"  formula bo'yicha kutilgan: {natija['jami_xato'] == kutilgan}")

    print("\n=== 3. Xotira (tracemalloc cho'qqisi) ===")
    print(f"  quvur 1 MB dan kam: {quvur_cho_qqisi < 1_000_000}")
    print(f"  ro'yxat usuli 50 MB dan ko'p: {royxat_cho_qqisi > 50_000_000}")
    print(f"  farq kamida 100 barobar: {royxat_cho_qqisi / quvur_cho_qqisi >= 100}")

    print("\n=== 4. Qoidalar ===")
    print("  ✅ manba — generator (fayl ham shunday o'qiladi)")
    print("  ✅ har tahlil uchun yangi quvur — iterator bir martalik")
    print("  ✅ groupby — jurnal vaqt bo'yicha tartiblangani uchun saralashsiz")
    print("  ✅ islice — kerakli miqdor topilgach, o'qish to'xtaydi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. 1 000 000 qatorli jurnal ===
  birinchi 3 xato: ["so'rov=0", "so'rov=997", "so'rov=1994"]
  eng zich daqiqa: ('2026-09-22T18:53', 20)
  xatolar orasidagi eng uzun tanaffus: 997 s
  500 talik paketlar: 3 ta, oxirgisi 24 ta yozuv
  jami xato: 1024

=== 2. Tekshiruvlar ===
  ro'yxat usuli bilan bir xil son: True
  formula bo'yicha kutilgan: True

=== 3. Xotira (tracemalloc cho'qqisi) ===
  quvur 1 MB dan kam: True
  ro'yxat usuli 50 MB dan ko'p: True
  farq kamida 100 barobar: True

=== 4. Qoidalar ===
  ✅ manba — generator (fayl ham shunday o'qiladi)
  ✅ har tahlil uchun yangi quvur — iterator bir martalik
  ✅ groupby — jurnal vaqt bo'yicha tartiblangani uchun saralashsiz
  ✅ islice — kerakli miqdor topilgach, o'qish to'xtaydi

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


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

Noto'g'ri fikr To'g'risi
"Generatorni ikki marta aylanish mumkin" Ikkinchi marta bo'sh
"x in iterator iteratorni o'zgartirmaydi" Topilgunicha elementlarni iste'mol qiladi
"groupby — SQL GROUP BY" Faqat ketma-ket kelganlarni
"groupby guruhlarini keyin o'qish mumkin" Keyingi guruhga o'tilgach bo'shaydi
"islice manfiy indeksni qo'llaydi" ValueError
"takewhile hech narsani yo'qotmaydi" Shartga to'g'ri kelmagan birinchi elementni yutadi
"zip uzunliklar farqini xabar qiladi" Jim qisqartiradi — strict=True
"tee bepul nusxa" O'qilmagan elementlar buferda saqlanadi

6. Keng tarqalgan xatolar va yechimlari

1. Iteratorni ikki marta ishlatish

python
sozlar = (s.strip() for s in f)
jami = sum(1 for _ in sozlar); noyob = set(sozlar)   # ❌ noyob — bo'sh
sozlar = [s.strip() for s in f]                     # ✅ kichik bo'lsa — list

2. Saralanmagan groupby

python
groupby(buyurtmalar, key=kun)                       # ❌
groupby(sorted(buyurtmalar, key=kun), key=kun)      # ✅

3. Guruhlarni saqlab qo'yish

python
guruhlar = list(groupby(xs, key=f))                 # ❌ guruhlar bo'shaydi
guruhlar = [(k, list(g)) for k, g in groupby(xs, key=f)]   # ✅

4. Cheksiz iteratorni to'liq o'qish

python
list(itertools.count())                             # ❌ xotira tugaydi
list(itertools.islice(itertools.count(), 10))       # ✅

5. Uzunlik farqini yashirish

python
for ism, ball in zip(ismlar, ballar): ...           # ⚠️ jim qisqaradi
for ism, ball in zip(ismlar, ballar, strict=True): ...   # ✅

6. Qo'lda paketlash

python
for i in range(0, len(xs), 1000): paket = xs[i:i+1000]   # ⚠️ faqat list uchun
for paket in itertools.batched(oqim, 1000): ...         # ✅ istalgan iterator

7. Katta faylni readlines

python
qatorlar = f.readlines()                            # ❌
for qator in f: ...                                 # ✅

8. tee va uzoqlashgan nusxalar

python
a, b = tee(katta_oqim); list(a); list(b)            # ⚠️ butun oqim xotirada

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 9-qism (o'tilgan): iterator protokoli va generatorlar
  • 11.8-dars (o'tilgan): xotira o'lchash, tracemalloc
  • 15.6–15.7-darslar (o'tilgan): defaultdict, deque
  • 15.9-dars: product, permutations, combinations
  • 15.10-dars: functools.reduce, partial
  • 16.8-dars: katta fayllarni oqim bilan o'qish
  • 23-qism: bazaga paketlab yozish
  • 24-qism: ma'lumot quvurlari va pandas ga o'tish

8. Eng yaxshi amaliyotlar

  1. Katta ma'lumot — dangasa quvur.

  2. Iterator bir martalik ekanini unutmang — har tahlilga yangi quvur yoki list.

  3. groupby dan oldin shu kalit bilan saralang — yoki ma'lumot allaqachon tartiblanganiga ishonch hosil qiling.

  4. zip(..., strict=True) — uzunliklar teng bo'lishi kerak bo'lganda.

  5. Paketlash — batched.

  6. Cheksiz iteratorlar — doim chegara bilan.

  7. Xotirani o'lchang (tracemalloc) — dangasalik foydasini taxmin qilmang.

  8. O'qilishi muhim — uzun itertools zanjirini nomli bosqichlarga bo'ling.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
import itertools as it
1.  print(list(it.islice(it.count(5), 3)))
2.  print(list(it.accumulate([2, 3, 4])))
3.  print(list(it.chain("ab", [1])))
4.  print([k for k, _ in it.groupby("aabaa")])
5.  print(list(it.takewhile(lambda x: x > 0, [3, 1, 0, 2])))
6.  print(list(it.dropwhile(lambda x: x > 0, [3, 1, 0, 2])))
7.  print(list(it.pairwise("abc")))
8.  print(list(it.batched("abcde", 2)))
9.  g = (x for x in [1, 2]); list(g); print(list(g))
10. i = iter([1, 2, 3]); print(2 in i, list(i))
11. print(list(it.zip_longest([1, 2], "a")))
12. print(list(it.compress("xyz", [0, 1, 1])))
Javoblar
  1. [5, 6, 7]
  2. [2, 5, 9]
  3. ['a', 'b', 1]
  4. ['a', 'b', 'a']
  5. [3, 1]
  6. [0, 2]
  7. [('a', 'b'), ('b', 'c')]
  8. [('a', 'b'), ('c', 'd'), ('e',)]
  9. []
  10. True [3]
  11. [(1, 'a'), (2, None)]
  12. ['y', 'z']

Vazifa 2: Xatolarni tuzating

python
1.  def kunlik_summa(buyurtmalar):           # (sana, summa), tartibsiz
        return {k: sum(s for _, s in g) for k, g in groupby(buyurtmalar, key=lambda b: b[0])}

2.  def statistika(sonlar_generatori):
        return sum(sonlar_generatori) / len(list(sonlar_generatori))

3.  def birinchi_10_xato(yol):
        return [q for q in open(yol).readlines() if "ERROR" in q][:10]

4.  def juftla(ismlar, telefonlar):
        return dict(zip(ismlar, telefonlar))  # uzunliklar teng bo'lishi shart

5.  def guruhlarni_ol(sozlar):
        return dict(groupby(sorted(sozlar), key=len))
Javoblar
python
1.  def kunlik_summa(buyurtmalar):
        kalit = lambda b: b[0]
        return {k: sum(s for _, s in g) for k, g in groupby(sorted(buyurtmalar, key=kalit), key=kalit)}

2.  def statistika(sonlar_generatori):
        sonlar = list(sonlar_generatori)          # yoki bitta aylanishda yig'indi va sanoq
        return sum(sonlar) / len(sonlar)

3.  def birinchi_10_xato(yol):
        with open(yol, encoding="utf-8") as f:
            return list(islice((q for q in f if "ERROR" in q), 10))

4.  def juftla(ismlar, telefonlar):
        return dict(zip(ismlar, telefonlar, strict=True))

5.  def guruhlarni_ol(sozlar):
        return {k: list(g) for k, g in groupby(sorted(sozlar, key=len), key=len)}

Vazifa 3: itertools ni qayta yozish

Faqat generatorlar bilan yozing va natijani asl funksiyalar bilan 100 ta tasodifiy kirishda solishtiring:

  1. mening_islice(it, start, stop, step)
  2. mening_groupby(it, key) — guruhlarni kech o'qish xulqi ham asl bilan bir xil bo'lsin
  3. mening_batched(it, n)
  4. mening_pairwise(it) — tee siz
  5. Tezlikni solishtiring va farq sababini tushuntiring

Vazifa 4: Sessiyalar

Foydalanuvchi harakatlari jurnalidan (vaqt bo'yicha tartiblangan (foydalanuvchi, vaqt)):

  1. Har foydalanuvchi uchun sessiyalarni ajrating: 30 daqiqadan ortiq tanaffus — yangi sessiya (pairwise + accumulate)
  2. Har sessiya uzunligi va harakatlar soni
  3. Eng uzun sessiyani toping
  4. Xotira O(bitta foydalanuvchi harakatlari) bo'lsin

Vazifa 5: CSV ni paketlab import qilish

  1. 1 mln qatorli CSV ni satrma-satr o'qing (16-qismdan oldin str.split(",") bilan)
  2. Sarlavhani islice bilan ajrating
  3. 10 000 talik paketlarda "bazaga yozing" (ro'yxatga)
  4. Noto'g'ri qatorlarni filterfalse bilan alohida faylga
  5. tracemalloc bilan xotira cho'qqisini readlines() usuli bilan solishtiring

Vazifa 6: Oqimdagi statistika

Cheksiz sensor oqimi (count + tasodifiy qiymatlar) uchun:

  1. Har 100 ta o'lchovdan keyin o'rtacha (batched)
  2. Kumulyativ maksimum (accumulate(max))
  3. Qiymat ketma-ket 5 marta chegaradan oshsa — ogohlantirish (groupby)
  4. Birinchi ogohlantirishgacha o'qing (takewhile)

Vazifa 7: O'ylash

Python'da map, filter, zip va range Python 2 da ro'yxat qaytarardi, Python 3 da esa dangasa obyekt (range — qayta o'qiladigan, qolganlari — bir martalik iterator). Bu o'zgarish nega qilingan, qanday xatolarni kamaytirdi va qanday yangi xatolarni keltirib chiqardi? Nega range boshqalardan farqli ravishda qayta o'qiladi?

Javob

Qisqa javob: Python 3 dangasalikni sukut qildi: xotira tejaldi, katta va cheksiz ketma-ketliklar bilan ishlash tabiiy bo'ldi. Narxi — "bir martalik" iteratorlar tufayli jim xatolar (ikkinchi aylanishda bo'sh natija). range esa ketma-ketlik (sequence) sifatida qayta ishlab chiqildi: u faqat start, stop, step ni saqlaydi va har iter() da yangi iterator beradi — shuning uchun ham dangasa, ham qayta o'qiladi.

1. Python 2 va 3

Funksiya Python 2 Python 3
range list (xrange — dangasa) Dangasa ketma-ketlik
map, filter list (itertools.imap — dangasa) Bir martalik iterator
zip list (izip) Bir martalik iterator
dict.keys() list Ko'rinish (view) — jonli, qayta o'qiladi

2. Nega o'zgartirildi

  1. Xotira: range(10**9) Python 2 da 1 mlrd elementli ro'yxat — imkonsiz
  2. Tezlik: for x in map(f, xs) — oraliq ro'yxat yaratilmaydi
  3. Birlashuvchanlik: dangasa bosqichlar quvur hosil qiladi, erta to'xtaydi
  4. Izchillik: xrange/range, imap/map kabi ikki xil nomlar yo'qoldi

3. Kamaygan xatolar

  • MemoryError va "sekin" skriptlar
  • Keraksiz nusxalar (zip(*...) uchun oraliq ro'yxatlar)

4. Paydo bo'lgan xatolar

Xato Belgisi
Ikkinchi aylanish bo'sh Hech qanday istisno yo'q — jim
len(map(...)) TypeError
in iste'mol qiladi Keyingi o'qishda elementlar yetishmaydi
Kechiktirilgan xato Istisno quvur qurilganda emas, o'qilganda chiqadi — traceback boshqa joyda
Yopilgan fayl ustidagi generator ValueError: I/O operation on closed file — with blokidan tashqarida o'qilganda

5. Nega range qayta o'qiladi

range — iterable ketma-ketlik, iterator emas:

Xususiyat range map
__iter__ Har safar yangi iterator self ni qaytaradi
len, indeks, kesma
in O(1) matematik tekshiruv Iste'mol qiladi
Holati O'zgarmas (start, stop, step) Joriy pozitsiya

Umumiy tamoyil: iterable (qayta aylanish mumkin — list, range, dict) va iterator (holatli, bir martalik) farqi. Iterator __iter__ da self qaytaradi.

6. Amaliy xulosa

  1. Funksiya argumentni ikki marta aylanishi kerak bo'lsa — Iterable emas, Sequence yoki Collection turini so'rang (13-qism)
  2. Yoki boshida list() ga aylantiring va buni hujjatlashtiring
  3. Qayta o'qiladigan dangasa obyekt kerak — __iter__ da har safar yangi generator qaytaruvchi sinf yozing
  4. Dangasa quvur xatolari kech chiqishini hisobga oling — chegaralarda tekshiring

Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.


Xulosa

Bu darsda itertools ning asosiy vositalari va dangasa quvurlar bilan ishlashni o'rgandik.

Eng muhim uch fikr:

  1. Dangasalik — kuch va tuzoq. itertools natijalari hech narsani oldindan hisoblamaydi: million qatorli jurnal quvuri bir megabaytdan kam xotirada ishladi, ro'yxat usuli esa o'nlab megabayt oldi. Lekin iteratorlar bir martalik: ikkinchi aylanish jim bo'sh natija beradi, in esa elementlarni iste'mol qiladi. Cheksiz count, cycle, repeat — doim islice yoki zip bilan chegaralanadi.

  2. Kesish, birlashtirish va paketlash. islice istalgan iteratorni kesadi (manfiy indekssiz), chain.from_iterable tekislaydi, pairwise qo'shni juftliklarni, batched paketlarni beradi. zip uzunliklar farqini jim yashiradi — strict=True uni xatoga aylantiradi. accumulate kumulyativ yig'indi, rekordlar va prefiks yig'indilar uchun; takewhile esa shartga mos kelmagan birinchi elementni yutib yuboradi.

  3. groupby — faqat ketma-ket kelganlar. U SQL GROUP BY emas: saralanmagan ma'lumotda bir kalit bir necha guruhga bo'linadi va lug'atga yig'ilganda oldingi qiymat jim almashtiriladi. Guruhlar keyingi guruhga o'tilgach bo'shaydi — ularni darhol o'qing. Tartiblangan oqimlar (vaqt bo'yicha jurnal, ketma-ketliklarni siqish) uchun groupby, tartibsiz ma'lumot uchun defaultdict(list).

Keyingi darsda itertools ning kombinatorika qismiga o'tamiz: product, permutations, combinations va variantlar sonining portlovchi o'sishi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
15.8-dars: itertools: asosiy — IlmHamroh