Iterators, Python’a iterasyon özelliği kazandıran bir nesnedir. Verileri döndüren nesne her seferinde bir öğe döndürür. Iterators, Pyhton programlama dilinde döngüler, liste, tüple ve generators gibi noktalarda karşımıza çıkar.
Python iterators nesnesi, __iter__() ve __next__() iki özel metot içerir. Bu metotlardan bir değer alabilirsek iterator özelliğindeki bir nesne içinde olduğumuzu gösterir. Örneğin Python’da liste, tuple ve string bu özelliğe sahiptir.
13.1.1. Bir iteratorle veriyi dolaşma
Bir iterator’ün tüm öğelerini manuel olarak dolaşmak için next() fonksiyonu kullanılır. En son veriye ulaştığımızda başka bir veri yoksa StopIteration exception’ı üretilir. Örneğin,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# Bir liste my_list = [14, 27, 230, 13] # iter() metodu ile bir iterator alınıyor my_iter = iter(my_list) #Next ile veriler dolaşılıyor print(next(my_iter)) print(next(my_iter)) ## next ile __next__() aynıdır. print(my_iter.__next__()) print(my_iter.__next__()) ## Bir hata oluşması beklenir next(my_iter) |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
14 27 230 13 --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-1-b3c83a00848f> in <module>() 15 16 ## Bir hata oluşması beklenir ---> 17 next(my_iter) StopIteration: |
Bu işlemi yapmanın bilinen yolu for döngüsü kullanmaktır. For döngüsü ile liste, tüple, dosya, string gibi veri türleri dolaşılabilir. Basit bir örnekle hatırlayalım:
1 2 |
for element in my_list: print(element) |
1 2 3 4 |
14 27 230 13 |
Aslında for olsun while oldun, iterator nesnesini kullanılır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
for element in iterable: # Kod # Bir iterator nesnesi yarat iter_obj = iter(iterable) # Sonsuz loop while True: try: # diğer öğeyi al element = next(iter_obj) # Kod # except StopIteration: # Eğer StopIteration oluşursa, Döngüden çık |
13.1.2. Kendimize ait bir iterator sınıfı
Verilen bir sayıya kadar olan sayıların küplerini bulan bir iterator sınıfı yapalım ve bu sınıfı hem next() metodu ile hem de for döngüsü ile dolaşalım. Öncelikle küp alma fonksiyonu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
class KupAl: 'Belirtilen sayıya kadar küp hesaplayan sınıf' def __init__(self, bitis = 0): self.bitis = bitis def __iter__(self): self.n = 0 return self def __next__(self): if self.n <= self.bitis: result = 2 ** self.n self.n += 1 return result else: raise StopIteration sayilar = KupAl(5) #iter i = iter(sayilar) print(next(i)) print(next(i)) print(next(i)) #döngü ile for i in KupAl(5): print(i) |
13.1.3. Sonsuz döngülü bir iterator sınıfı
Bir önceki örnekte belli bir n sayısına kadar sınıf belirlemiştik. Bu örnekte sınırları kaldırıyoruz:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class SonsuzIter: 'Çift sayıları döndüren bir iterator' def __iter__(self): self.i = 0 return self def __next__(self): self.i += 2 return self.i a = iter(SonsuzIter()) print(next(a)) print(next(a)) print(next(a)) |
1 2 3 |
2 4 6 |
Sonsuz döngü olduğu için döngü kullanırken dikkatli olun. Iterator kullanmanın en güzel yanı kaynaklardan tasarruf etmektir. Normal şartlarda tüm çift sayıları bir bellek alanında saklamak çok maliyetlidir. Iterator’ler sayesinde sadece ufak bir bellek bölgesi ile (sınıf için açılmış nesne kadar) tüm sayılara erişmek mümkündür. Ancak listedeki gibi tüm sayılar elimizde değildir. Örneğin 790 posizyonunda bulunan kaydı çek dediğiniz 791 defa next metodunu çalıştırmanız gerekir.