Iterator ба Generator
for давталт ашиглахдаа та жагсаалт, мөр, dict зэрэг объектуудаар давтана. Эдгээр бүгд iterable — давтагдах чадвартай объект. Энэ хичээлд тэдгээрийн дотоод механизм болон хэрхэн өөрийн iterator, generator үүсгэхийг сурна.
Iterator гэж юу вэ?
Iterator нь __iter__() ба __next__() методтой объект юм. for давталт энэ хоёр методыг дуудаж ажилладаг.
жагсаалт = [1, 2, 3]
iterator = iter(жагсаалт) # __iter__() дуудна
print(next(iterator)) # 1 — __next__() дуудна
print(next(iterator)) # 2
print(next(iterator)) # 3
# next(iterator) → StopIteration алдаа өгнө
for давталт дотооддоо яг ийм зүйл хийдэг — StopIteration гарахад давталт зогсдог.
Өөрийн iterator класс үүсгэж болно:
class Тоолуур:
def __init__(self, эхлэл, төгсгөл):
self.одоо = эхлэл
self.төгсгөл = төгсгөл
def __iter__(self):
return self
def __next__(self):
if self.одоо >= self.төгсгөл:
raise StopIteration
утга = self.одоо
self.одоо += 1
return утга
for тоо in Тоолуур(1, 5):
print(тоо)
# 1
# 2
# 3
# 4
Generator — хялбар арга
Iterator бичих нь харьцангуй их код шаарддаг. Generator нь үүнийг маш хялбаршуулна — yield түлхүүр үгийг ашигладаг.
def тоолуур(эхлэл, төгсгөл):
одоо = эхлэл
while одоо < төгсгөл:
yield одоо # утга буцааж, түр зогсоно
одоо += 1
for тоо in тоолуур(1, 5):
print(тоо)
# 1
# 2
# 3
# 4
yield нь return-тэй адилхан боловч функцийг устгахгүй — дараагийн удаа дуудахад зогссон газраасаа үргэлжилнэ. Энэ нь маш хүчирхэг ойлголт!
Generator expression
List comprehension шиг бичиж generator үүсгэж болно:
# List comprehension — бүх утгыг санах ойд хадгална
дөрвөлжин_жагсаалт = [x**2 for x in range(10)]
# Generator expression — нэг нэгээр үүсгэнэ (санах ой хэмнэнэ)
дөрвөлжин_gen = (x**2 for x in range(10))
print(sum(дөрвөлжин_gen)) # 285
Их өгөгдөлтэй ажиллахад generator ашиглах нь санах ойн хэрэглээг эрс багасгана — бүх утгыг нэгэн зэрэг хадгалахгүй, шаардлагатай үед нэг нэгээр үүсгэдэг.
Практик жишээ — хязгааргүй дараалал
Generator-ийн нэг давуу тал: хязгааргүй дараалал үүсгэж болно.
def фибоначи():
а, б = 0, 1
while True: # хязгааргүй давталт!
yield а
а, б = б, а + б
ген = фибоначи()
for _ in range(8):
print(next(ген), end=" ")
# 0 1 1 2 3 5 8 13
List-ээр хязгааргүй дараалал хадгалах боломжгүй — санах ой дуусна. Гэвч generator нь зөвхөн одоогийн утгыг санаж байдаг тул асуудалгүй.
Дараагийн хичээлд:
Decorator үндэс — функцийн боловсруулалтыг хэрхэн хялбархан нэмэх, @ тэмдэгтийн ард юу нуугддаг болохыг сурна.