Generatorlar bilan tanishish
Pythonda, generator — aylanib chiqilganda qiymatlar ketma-ketligini ishlab chiqaruvchi iteratorni qaytaruvchi funksiya.
Generatorlar katta hajmdagi qiymatlar ketma-ketligini ishlab chiqarishni xohlaganimizda, lekin ularning barchasini bir vaqtning o'zida xotirada saqlashni xohlamaganimizda foydali.
Pythonda, oddiy funksiyani aniqlashga o'xshab, generator funksiyasini def kalit so'zi yordamida aniqlashimiz mumkin, lekin return operatori o'rniga yield operatoridan foydalanamiz.
def generator_name(arg):
# operatorlar
yield something
Bu yerda, yield kalit so'zi generatordan qiymat ishlab chiqarish uchun ishlatiladi.
Generator funksiyasi chaqirilganda, u funksiya tanasini darhol bajarmaydi. Buning o'rniga, u qiymatlarni ishlab chiqarish uchun aylanib chiqilishi mumkin bo'lgan generator obyektini qaytaradi.
Misol: Python generatori
Mana sonlar ketma-ketligini ishlab chiqaruvchi generator funksiyasiga misol,
def my_generator(n):
# hisoblagichni ishga tushirish
value = 0
# hisoblagich n dan kichik bo'lguncha aylanish
while value < n:
# hisoblagichning joriy qiymatini ishlab chiqarish
yield value
# hisoblagichni oshirish
value += 1
# my_generator tomonidan ishlab chiqarilgan generator obyekti bo'ylab aylanib chiqish
for value in my_generator(3):
# generator ishlab chiqargan har bir qiymatni chop etish
print(value)
Natija
0
1
2
Yuqoridagi misolda, my_generator() generator funksiyasi n integerini argument sifatida oladi va while sikli yordamida 0dan n-1gacha sonlar ketma-ketligini ishlab chiqaradi.
yield kalit so'zi generatordan qiymat ishlab chiqarish va keyingi qiymat so'ralguncha generator funksiyasining bajarilishini to'xtatib turish uchun ishlatiladi.
for sikli my_generator() ishlab chiqargan generator obyekti bo'ylab aylanib chiqadi, print operatori esa generator ishlab chiqargan har bir qiymatni chop etadi.
Biz shuningdek generator funksiyasidan generator obyektini boshqa har qanday funksiya kabi chaqirish orqali ham yaratishimiz mumkin,
generator = my_range(3)
print(next(generator)) # 0
print(next(generator)) # 1
print(next(generator)) # 2
Eslatma: Ko'proq bilish uchun, range() va for loop() sahifalariga tashrif buyuring.
Pythonda, generator ifodasi generator obyektini yaratishning ixcham usuli.
U list comprehension'ga o'xshaydi, lekin ro'yxat yaratish o'rniga, u generator ichidagi qiymatlarni ishlab chiqarish uchun aylanib chiqilishi mumkin bo'lgan generator obyektini yaratadi.
Generator ifodasi sintaksisi
Generator ifodasi quyidagi sintaksisga ega,
(ifoda for element iterable'da)
Bu yerda, ifoda — iterable'dagi har bir element uchun qaytariladigan qiymat.
Generator ifodasi aylanib chiqilganda, iterable'dagi har bir element uchun ifodaning qiymatlarini birma-bir ishlab chiqaruvchi generator obyektini yaratadi.
2-misol: Python generator ifodasi
# generator obyektini yaratish
squares_generator = (i * i for i in range(5))
# generator bo'ylab aylanib chiqish va qiymatlarni chop etish
for i in squares_generator:
print(i)
Natija
0
1
4
9
16
Bu yerda, biz aylanib chiqilganda 0 dan 4gacha bo'lgan sonlarning kvadratlarini ishlab chiqaradigan generator obyekti yaratdik.
Va keyin, generator bo'ylab aylanib chiqish va qiymatlarni olish uchun for siklidan foydalandik.
Generatorlarni kuchli implementatsiya qiluvchi bir necha sabab bor.
1. Amalga oshirish oson
Generatorlarni ularning iterator klassi hamkasbiga qaraganda aniqroq va ixchamroq tarzda amalga oshirish mumkin. Quyida 2ning darajalari ketma-ketligini iterator klassi yordamida amalga oshirishga misol keltirilgan.
class PowTwo:
def __init__(self, max=0):
self.n = 0
self.max = max
def __iter__(self):
return self
def __next__(self):
if self.n > self.max:
raise StopIteration
result = 2 ** self.n
self.n += 1
return result
Yuqoridagi dastur cho'zilgan va chalkash edi. Endi, keling xuddi shuni generator funksiyasi yordamida bajaramiz.
def PowTwoGen(max=0):
n = 0
while n < max:
yield 2 ** n
n += 1
Generatorlar tafsilotlarni avtomatik kuzatib borgani uchun, implementatsiya ixcham va ancha tozaroq bo'ldi.
2. Xotiraga tejamkor
Ketma-ketlikni qaytaruvchi oddiy funksiya natijani qaytarishdan oldin butun ketma-ketlikni xotirada yaratadi. Agar ketma-ketlikdagi elementlar soni juda katta bo'lsa, bu haddan tashqari ortiqcha.
Bunday ketma-ketliklarning generator implementatsiyasi xotiraga do'stona va afzal ko'riladi, chunki u bir vaqtning o'zida faqat bitta elementni ishlab chiqaradi.
3. Cheksiz oqimni ifodalash
Generatorlar cheksiz ma'lumotlar oqimini ifodalash uchun ajoyib vositalar. Cheksiz oqimlarni xotirada saqlab bo'lmaydi, va generatorlar bir vaqtning o'zida faqat bitta elementni ishlab chiqargani uchun, ular cheksiz ma'lumotlar oqimini ifodalashi mumkin.
Quyidagi generator funksiyasi barcha juft sonlarni (kamida nazariy jihatdan) generatsiya qilishi mumkin.
def all_even():
n = 0
while True:
yield n
n += 2
4. Generatorlarni quvur (pipeline) qilish
Bir nechta generatorlardan bir qator amallarni quvurlash (pipelining) uchun foydalanish mumkin. Buni misol bilan eng yaxshi tushuntirish mumkin.
Aytaylik, bizda Fibonachchi qatoridagi sonlarni ishlab chiqaruvchi generator bor. Va bizda sonlarni kvadratga oshiruvchi boshqa generator bor.
Agar Fibonachchi qatoridagi sonlarning kvadratlari yig'indisini topmoqchi bo'lsak, buni generator funksiyalarining natijasini birga quvurlash orqali quyidagi tarzda qilishimiz mumkin.
def fibonacci_numbers(nums):
x, y = 0, 1
for _ in range(nums):
x, y = y, x+y
yield x
def square(nums):
for num in nums:
yield num**2
print(sum(square(fibonacci_numbers(10))))
# Natija: 4895
Bu quvurlash samarali va o'qish oson (va, ha, ancha zo'r!).