Iterator در مقابل iterable
لیست ها (Lists)، چندتایی ها (Tuples)، فرهنگ لغت ها (Dictionaries) و مجموعه ها (Sets) همه اشیاء قابل تکرار یا در اصطلاح iterable هستند.
این ها ظرف های قابل تکرار (iterable) هستند که می توانید از آن ها یک تکرار کننده (iterator) تهیه کنید.
همه این اشیاء دارای یک متد با نام ()iter هستند که برای به دست آوردن یک تکرار کننده (iterator) مورد استفاده قرار می گیرد.
مثال: در این مثال در یک چندتایی (Tuple) یک تکرار کننده (iterator) را به دست می آورد و هر کدام از مقادیر آن را به صورت تکی چاپ می کند.
mytuple = ("apple", "banana", "cherry")
myit = iter(mytuple)
print(next(myit))
print(next(myit))
print(next(myit))
حتی رشته ها (Strings) هم جزو اشیاء قابل تکرار (iterable) هستند و می توان از آن ها یک تکرار کننده (iterator) به دست آورد.
مثال: از رشته “banana” که دنباله ای از کاراکتر ها است یک تکرار کننده (iterator) به دست می آورد و کاراکترهای آن را به صورت تکی در خروجی چاپ می کند.
mystr = "banana"
myit = iter(mystr)
print(next(myit))
print(next(myit))
print(next(myit))
print(next(myit))
print(next(myit))
print(next(myit))
پیمایش یک iterator
همچنین می توانیم برای پیمایش یک شی قابل تکرار (iterable) از حلقه for در پایتون استفاده کنیم.
مثال: در این مثال مقادیر چندتایی (Tuple) مثال بالا را این بار با حلقه for پیمایش کرده ایم.
mytuple = ("apple", "banana", "cherry")
for x in mytuple:
print(x)
مثال: در این مثال نیز این بار کاراکترهای رشته “banana” را با حلقه for پیمایش کرده ایم و به صورت تکی آن ها را چاپ کرده ایم.
mystr = "banana"
for x in mystr:
print(x)
در واقع حلقه for یک شی تکرار کننده ایجاد می کند و متد ()next را در هر بار تکرار حلقه اجرا می کند.
ایجاد یک تکرار کننده (iterator) در پایتون
برای ایجاد یک شی/کلاس به عنوان یک تکرار کننده (iterator) باید متدهای ()__iter__ و ()__next__ را برای شی خودتان پیاده سازی کنید.
همانطور که در مقاله کلاس ها و اشیاء در پایتون یاد گرفتید، همه کلاس ها تابعی با نام ()__init__ دارند، که به شما اجازه می دهد مقداردهی های اولیه را در هنگام ایجاد شی انجام دهید.
متد ()__iter__ عملکردی مشابه ()__init__ دارد که شما می توانید مقداردهی اولیه و کارهایی از این قبیل را انجام دهید اما همیشه باید شی تکرار کننده (iterator) را خودتان برگردانید.
متد ()__next__ به شما اجازه انجام عملیات می دهد، و باید آیتم های بعدی را به ترتیب برگردانید.
مثال: در زیر یک تکرار کننده (iterator) ایجاد کرده ایم که اعداد را برمیگرداند، اعداد از 1 شروع می شوند و در هر دنباله یک واحد به عدد 1 اضافه می شود (1, 2, 3, 4, 5, …)
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
myclass = MyNumbers()
myiter = iter(myclass)
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
دستور stopiteration
در مثال بالا اگر برای شما دستورهای ()next کافی داشته باشد با اگر از حلقه for در آن استفاده شده باشد، این حلقه تا بی نهایت ادامه پیدا می کند.
برای جلوگیری از ادامه تکرار تا بی نهایت از دستور stopiteration استفاده می کنیم.
در متد ()__next__ ، اگر قرار است تکرار به تعداد دفعات مشخص انجام شود، می توانیم برای جلوگیری از اجرای بیشتر یک شرط فسخ ایجاد کنیم.
مثال: در این مثال حلقه به تعداد 20 بار تکرار می شود و نه بیشتر.
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration
myclass = MyNumbers()
myiter = iter(myclass)
for x in myiter:
print(x)