Python / Iterator ба Generator

Iterator ба Generator

for давталт ашиглахдаа та жагсаалт, мөр, dict зэрэг объектуудаар давтана. Эдгээр бүгд iterable — давтагдах чадвартай объект. Энэ хичээлд тэдгээрийн дотоод механизм болон хэрхэн өөрийн iterator, generator үүсгэхийг сурна.

Iterator гэж юу вэ?

Iterator нь __iter__() ба __next__() методтой объект юм. for давталт энэ хоёр методыг дуудаж ажилладаг.

python
жагсаалт = [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 класс үүсгэж болно:

python
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 түлхүүр үгийг ашигладаг.

python
def тоолуур(эхлэл, төгсгөл):
    одоо = эхлэл
    while одоо < төгсгөл:
        yield одоо        # утга буцааж, түр зогсоно
        одоо += 1

for тоо in тоолуур(1, 5):
    print(тоо)
# 1
# 2
# 3
# 4

yield нь return-тэй адилхан боловч функцийг устгахгүй — дараагийн удаа дуудахад зогссон газраасаа үргэлжилнэ. Энэ нь маш хүчирхэг ойлголт!

Generator expression

List comprehension шиг бичиж generator үүсгэж болно:

python
# 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-ийн нэг давуу тал: хязгааргүй дараалал үүсгэж болно.

python
def фибоначи():
    а, б = 0, 1
    while True:          # хязгааргүй давталт!
        yield а
        а, б = б, а + б

ген = фибоначи()

for _ in range(8):
    print(next(ген), end=" ")
# 0 1 1 2 3 5 8 13

List-ээр хязгааргүй дараалал хадгалах боломжгүй — санах ой дуусна. Гэвч generator нь зөвхөн одоогийн утгыг санаж байдаг тул асуудалгүй.

Дараагийн хичээлд:

Decorator үндэс — функцийн боловсруулалтыг хэрхэн хялбархан нэмэх, @ тэмдэгтийн ард юу нуугддаг болохыг сурна.