5.1 Iterable
və Iterator
Artıq bildiyiniz kimi, iteratorlar — bu, iterasiya protokolunu reallaşdıran obyektlərdir ki, koleksiyadan ardıcıl olaraq elementləri əldə etməyə imkan yaradır. Iteratorlar Python-da ardıcıllıqların elementlərini keçmək üçün geniş istifadə olunur, məsələn list, tuple və string.
Gəlin iteratorların necə qurulduğunu və onlardan necə istifadə edəcəyimizi araşdıraq.
İterasiya olunabilən obyekt (Iterable)
Bir obyektin üzərində for
dövrü ilə keçmək üçün, o, iterasiya olunabilən – Iterable
olmalıdır. Yəni, bizim obyekt __iter__()
metodunu reallaşdırmalıdır ki, bu da iterator obyektini qaytarır.
Iterator obyekt (Iterator)
Bu xüsusi bir obyekt olur ki, __next__()
funksiyasına malikdir və bu funksiya ardıcıllıqda növbəti elementi qaytarır. Elementlər bitdiyi zaman, __next__()
metodu iterasiyanın dayandırıldığına işarə olaraq StopIteration
istisnasını atır.
Iterator həmçinin özünü qaytaran __iter__()
metodunu reallaşdırmalıdır.
Python-un daxili funksiyaları ilə nümunə
Bu nümunədə numbers list iterasiya olunabilən obyekt kimi çıxış edir. Biz iteratoru iter()
funksiyası ilə alırıq və next()
funksiyasından istifadə edərək elementlərin üzərində StopIteration
istisnası atılana qədər iterasiya edirik.
# İterasiya olunabilən obyekt
numbers = [1, 2, 3, 4, 5]
# İterasiya olunabilən obyektin iteratorunu əldə edirik
iterator = iter(numbers)
# Elementlərin üzərində iterator vasitəsilə keçiririk
try:
while True:
number = next(iterator)
print(number)
except StopIteration:
pass
Bu, məhz aşağıdakı kodu yazdığınız zaman baş verir:
# İterasiya olunabilən obyekt
numbers = [1, 2, 3, 4, 5]
for number in numbers:
print(number)
5.2 Iteratorun mahiyyəti
Iterator — bu hansısa bir obyektir ki, bizə elementlər qrupunu bir-bir gəzməyə kömək edir. Onun reallaşdırılması çox fərqli şəkildə ola bilər. Gəlin öz class-ımızı yazaq və orada iterator üçün tələb olunan bütün tələbləri həyata keçirək.
Adım 1. İlk öncə öz class-ımızı yaradaq
İcazə verin, o start
-dan end
-ə qədər nömrələri bir-bir qaytarsın.
class MyIterator:
def __init__(self, start, end):
self.current = start
self.end = end
Adım 2. __iter__
funksiya dəstəyi
İndi biz ona __iter__
funksiyasını əlavə etməliyik, hansı ki iterator obyektini qaytaracaq ki, onun üzərində __next()__
funksiyası çağırılsın. Biz öz obyektimizə istinad qaytaracağıq – bu qadağan deyil.
class MyIterator:
def __init__(self, start, end):
self.current = start
self.end = end
def __iter__(self):
return self
Adım 3. __next__
funksiya dəstəyi
İndi iterator obyektimizə __next__
funksiyasını əlavə etmək lazımdır, hansı ki, növbəti elementi qaytaracaq. Biz sadəcə current
dəyişənindən istifadə edəcəyik:
def __next__(self):
current = self.current
self.current += 1
return current
Adım 4. Iteratorun dayandırılması
Əgər iterator artıq qaytarmaq istədiyi bütün dəyərləri qaytarıbsa, o StopIteration
istisnası atmalıdır. Gəlin sonuncu funksiyamızı bir az dəyişək:
def __next__(self):
if self.current >= self.end: raise StopIteration
current = self.current
self.current += 1
return current
Əla. İndi öz iteratorumuzdan istifadə edə bilərik. Bütün kodumuzun nümunəsini göstəririk:
class MyIterator:
def __init__(self, start, end):
self.current = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.current >= self.end:
raise StopIteration
current = self.current
self.current += 1
return current
# Custom iterator-ın nümunəsini yaradırıq
my_iter = MyIterator(1, 5)
# Elementləri keçmək üçün iterator istifadə edirik
for num in my_iter:
print(num)
5.3 Düzgün iterator
Əvvəlki nümunədəki iterator nə üçün yaxşı deyil? Bəli, bu bir iterator-dur, işləyir, amma çox primitivdir. Onunla eyni elementlər kolleksiyasını fərqli iteratorlarla eyni zamanda keçmək mümkün deyil.
Daha düzgün olardı ki, __iter__
metodunda özünə deyil, ayrı bir obyektə link qaytaran kod yazaq, hansı ki, düzgün şəkildə bütün elementləri qaytarar.
Nümunə:
class MyIterable:
def __init__(self, data):
self.data = data
def __iter__(self):
return MyIterator(self.data)
class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.data):
raise StopIteration
item = self.data[self.index]
self.index += 1
return item
# İstifadə
my_iterable = MyIterable([1, 2, 3, 4])
for item in my_iterable:
print(item)
Bu nümunədə iki sinifimiz var — birincisinə iterator vasitəsilə keçəcəyimiz kolleksiya ötürülür. İkincisi — bu artıq iteratorun özüdür, hansı ki next()
metodunda kolleksiyanın elementlərini qaytarır. O da kifayət qədər sadədir, amma iteratorları siniflərinizə əlavə etməyin düzgün yolu məhz budur.
GO TO FULL VERSION