Python'da iterator va generator'lar xotira tejamkorligi (memory efficiency) uchun juda muhim. Ular katta hajmdagi ma'lumotni (hatto cheksiz ketma-ketliklarni ham) hammasini bir yo'la RAM'ga yuklamasdan, bo'laklab qayta ishlashga imkon beradi.
Qalin kitobni o'qish misolini oling: iterator sizga sahifa-sahifa o'qishga (faqat bitta sahifani xotirada ushlab turishga) yordam beradi. 1000 sahifani birdan yodlab olish shart emas.
1. Iterators
Iterator — sanab bo'ladigan qiymatlarni ketma-ket beradigan obyekt. U ustidan iteratsiya qilish, ya'ni qiymatlarni navbatma-navbat ko'rib chiqish mumkin.
Texnik jihatdan, Python'da iterator — iterator protokolini amalga oshiradigan obyekt bo'lib, __iter__() va __next__() metodlariga ega bo'ladi.
Iterator yaratish misoli
Quyida 1 dan boshlab berilgan limitgacha son qaytaradigan oddiy iterator:
class MyNumbers:
def __init__(self, limit):
self.limit = limit
self.num = 1
def __iter__(self):
return self
def __next__(self):
if self.num <= self.limit:
x = self.num
self.num += 1
return x
else:
raise StopIteration
myclass = MyNumbers(3)
myiter = iter(myclass)
print(next(myiter)) # Natija: 1
print(next(myiter)) # Natija: 2
print(next(myiter)) # Natija: 3
# print(next(myiter)) # StopIteration xatosi chiqaradi
for siklidan foydalanganda Python __iter__() va StopIteration exception'ini avtomatik boshqaradi.
for x in MyNumbers(3):
print(x)
2. Generators
Generator — iterator yaratishning sodda usuli. __iter__() va __next__() bilan katta sinf yozish o'rniga, oddiy funksiya yozasiz va qiymat qaytariladigan joyda yield ishlatasiz.
Har safar yield chaqirilganda funksiya "pauza" qiladi, o'zgaruvchilar holatini saqlab qoladi va keyingi chaqiriqda o'sha joydan davom etadi.
Oddiy generator misoli
def number_generator(limit):
num = 1
while num <= limit:
yield num
num += 1
gen = number_generator(3)
# Generator ham iterator!
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
Generator afzalligi: xotirani tejash
Masalan, 1 million sonni qayta ishlashingiz kerak.
Ro'yxat bilan (xotira ko'p sarflanadi):
def get_list():
result = []
for i in range(1000000):
result.append(i)
return result
# Bu butun sonlar ro'yxati uchun taxminan 40MB+ xotira sarflaydi
Generator bilan (xotirani tejaydi):
def get_generator():
for i in range(1000000):
yield i
# Bu deyarli qo'shimcha xotira sarflamaydi, chunki sonlar so'ralganda bittadan hosil qilinadi.
3. Generator expression
List comprehensionga o'xshaydi, lekin () ishlatiladi. Natija ro'yxat emas, generator obyekti bo'ladi.
# List comprehension (to'liq list'ni xotirada yaratadi)
squares_list = [x**2 for x in range(10)]
print(squares_list) # [0, 1, 4, ..., 81]
# Generator expression (lazy evaluation)
squares_gen = (x**2 for x in range(10))
print(squares_gen) # <generator object ...>
# Tarkibini ko'rish uchun iteratsiya qilish kerak
for i in squares_gen:
print(i, end=" ")
4. Amaliy holat: katta fayllarni o'qish
Masalan, 10GB server log faylini qayta ishlash kerak bo'lsa:
Noto'g'ri (bunday qilmang):
server.log fayli mavjud deb hisoblaydi. Fayl bo'lmasa, bajarilganda xato yuzaga keladi.def read_file_wrong(filename):
file = open(filename)
content = file.read() # Xavfli! Butun 10GB ni RAM ga yuklaydi.
return content.split("\n")
To'g'ri (generator ishlating):
server.log papkangizda mavjud bo'lmasa, FileNotFoundError chiqaradi.def read_file_right(filename):
with open(filename, "r", encoding="utf-8") as handle:
for line in handle:
yield line
with open("server.log", "w", encoding="utf-8") as handle:
handle.write("INFO Started\n")
handle.write("ERROR Disk nearly full\n")
handle.write("INFO Completed\n")
# 10GB faylni xotira muammolarsiz o'qishimiz mumkin
for line in read_file_right("server.log"):
if "ERROR" in line:
print(line)
5. Cheksiz generatorlar
Qiymatlar talab bo'yicha hosil qilinganligi sababli, generator cheksiz ketma-ketlikni ifodalashi mumkin. Qachon to'xtashni chaqiruvchi hal qiladi:
def count_up(start=0):
num = start
while True: # o'zi hech qachon tugamaydi
yield num
num += 1
gen = count_up(10)
print(next(gen)) # 10
print(next(gen)) # 11
print(next(gen)) # 12
Cheksiz generator bo'ylab for sikli o'zi break qilishi shart, aks holda u cheksiz ishlaydi:
def count_up(start=0):
num = start
while True:
yield num
num += 1
for n in count_up():
if n > 3:
break
print(n) # 0 1 2 3
6. yield from bilan delegatsiya
Bitta generator boshqa iterable'ning barcha qiymatlarini berishi kerak bo'lganda, yield from buni qo'lda sikl o'rniga bitta qatorda bajaradi:
def letters():
yield from "AB"
def numbers():
yield from range(1, 3)
def combined():
yield from letters()
yield from numbers()
print(list(combined())) # ['A', 'B', 1, 2]
Bu generator quvurlarini tekis va o'qilishi qulay saqlaydi hamda ayniqsa ichma-ich ma'lumotni tekislashda foydali.
Xulosa
- Iterator: iteratsiya qilinadigan obyekt (
__next__). - Generator: qiymatlarni talab bo'yicha birma-bir beradigan funksiya (
yield). yield from: qo'lda siklsiz boshqa iterable'ga delegatsiya qiladi.- Katta ma'lumotlar to'plami yoki cheksiz ma'lumot oqimi bilan ishlaganda generatorlardan foydalaning.
Oxirgi yangilangan: 14-iyul, 2026