Asosiy kontentga o‘tish
Innovialabs

Python generatorlari va yield: katta ma’lumotni tejamkor ishlash

Amaliyot3 daq

Qisqacha

Generator qiymatlarni yield orqali bittadan beradi va butun to‘plamni xotirada saqlamaydi, shuning uchun istalgan hajmdagi faylni deyarli doimiy xotira sarfi bilan qatorma-qator qayta ishlash mumkin.

Qisqacha javob

Generator — yield li funksiya bo‘lib, qiymatlarni so‘ralganda bittadan qaytaradi. Keyingi elementni so‘ramaguningizcha kod bajarilmaydi. Shuning uchun generator butun to‘plamni xotiraga yuklamaydi: gigabaytlik faylni qayta ishlash taxminan bitta qatorni qayta ishlashchalik xotira oladi.

Iterable, iterator, generator

TushunchaNimaMisol
Iterablesikl bilan aylanib chiqish mumkin bo‘lgan obyekt, unda __iter__ borlist, str, dict, fayl
Iteratorkeyingi elementni qaytaradigan va o‘rnini eslab qoladigan __next__ li obyektiter([1, 2, 3])
Generatoryield li funksiya yoki generator ifodasi yaratgan iterator(x * 2 for x in data)

Ro‘yxatni istalgancha aylanib chiqish mumkin. Iterator va generator esa faqat bir marta ishlaydi: tugagach, ular bo‘sh.

yield qanday ishlaydi

def countdown(n):
    while n > 0:
        yield n
        n -= 1

gen = countdown(3)
next(gen)  # 3
next(gen)  # 2

countdown(3) chaqiruvi hech narsa hisoblamaydi — u generator obyektini qaytaradi. Har bir next() tanani eng yaqin yield gacha bajaradi, qiymatni beradi va funksiya holatini muzlatadi. Tana tugaganda StopIteration ko‘tariladi va for sikli o‘zi to‘xtaydi.

Generator ifodalari

Kvadrat qavslar ro‘yxat yaratadi, oddiy qavslar — generator:

squares_list = [x * x for x in range(10_000_000)]  # hammasi xotirada
squares_gen = (x * x for x in range(10_000_000))   # bittadan

total = sum(x * x for x in range(10_000_000))     # qavslarni tushirish mumkin

Natija bir marta kerak bo‘lsa — sum, max, any yoki faylga yozish uchun — generator ifodasidan foydalaning.

Katta fayl uchun lazy konveyer

Generatorlarning asosiy kuchi — ularni zanjirga ulash mumkin. Har bir qadam oqimni qabul qilib, oqim qaytaradi:

import csv

def read_rows(path):
    with open(path, newline="", encoding="utf-8") as f:
        yield from csv.DictReader(f)

def only_paid(rows):
    for row in rows:
        if row["status"] == "paid":
            yield row

def amounts(rows):
    for row in rows:
        yield float(row["amount"])

total = sum(amounts(only_paid(read_rows("orders.csv"))))

Hech bir qadamda butun fayl xotirada bo‘lmaydi: qator o‘qiladi, filtrlanadi, o‘zgartiriladi va darhol qo‘shiladi. Xuddi shu yondashuv loglar uchun ham ishlaydi:

def errors(path):
    with open(path, encoding="utf-8") as f:
        for line in f:
            if " ERROR " in line:
                yield line.rstrip()

Haqiqiy kodda pul summalari uchun float emas, Decimal afzal — bu yerda float faqat qisqalik uchun.

yield from

yield from iterable boshqa iteratorning barcha elementlarini beradi. Bu sikldan qisqaroq va rekursiya hamda generatorni qismlarga bo‘lish uchun qulay:

def walk(tree):
    yield tree.value
    for child in tree.children:
        yield from walk(child)

Bundan tashqari, yield from ichki generatorning send(), istisnolari va qaytariladigan qiymatini to‘g‘ri uzatadi.

Ko‘p uchraydigan tuzoqlar

  • Bir martalik. Xuddi shu generatorni ikkinchi marta aylanib chiqish hech narsa bermaydi:
gen = (x for x in range(3))
list(gen)  # [0, 1, 2]
list(gen)  # []

Ma’lumot ikki marta kerak bo‘lsa, generatorni qaytadan yarating yoki xotiraga sig‘sa, ro‘yxatga saqlang.

  • Yopilgan fayl. Agar funksiya faylni with bilan ochib, blok ichida yield qilmasdan generator qaytarsa, fayl o‘qilishidan oldin yopiladi. yield ni with bloki ichida saqlang.
  • len() va indekslar ishlamaydi. Generatorning uzunligi yo‘q, gen[5] xato beradi. Kesimlar uchun itertools.islice bor.
  • Kechikkan xatolar. Istisno generator yaratilganda emas, element o‘qilganda yuzaga keladi, shuning uchun traceback kutilmagan joyni ko‘rsatishi mumkin.
  • print(gen) bilan debugging faqat <generator object ...> ni ko‘rsatadi, ma’lumotni emas.

Generator yoki ro‘yxat

  • Ma’lumot katta yoki cheksiz — generator.
  • Bitta o‘tish va yig‘indi natija kerak — generator.
  • Takroriy o‘tishlar, saralash, len yoki indekslar kerak — ro‘yxat.
  • Ma’lumot kam — farq sezilmaydi, o‘qilishi osonini tanlang.

Ko‘p beriladigan savollar

Yo‘q. Generator xotirani tejaydi, lekin har bir element uchun kichik qo‘shimcha xarajat bor. Kichik ma’lumotlar uchun ro‘yxat ko‘pincha xuddi shunday tez va qulayroq.

Bunda yordam beramiz

O‘zingiz shug‘ullanmasdan natija olishni istasangiz — biz har kuni shu bilan shug‘ullanamiz.

Loyihani muhokama qilish

Yana o‘qing

G‘oya yoki vazifangiz bormi? Bizga aytib bering

Ish kuni davomida javob beramiz va yechim taklif qilamiz. Konsultatsiya bepul.