iterator ها در پایتون

در پایتون همانند هر زبان برنامه نویسی دیگری از حلقه for برای پیشمایش بر روی عناصر یک مجموعه از عناصر استفاده کنیم. به طور مثال برای پیمایش بر روی عناصر لیست ها، تاپل ها، دیکشنری ها و کاراکترهای یک رشته از حلقه تکرار for استفاده کنیم. Iterator به معنی تکرار کننده است و در پایتون لیست ها، تاپل ها و دیکشنری ها انواع درونی (built-in) هستند که در واقع یک iterator هستند و می توانیم حلقه تکرار for را برای پیمایش و دسترسی به عناصر آنها استفاده کنیم.

مفهوم iterator در پایتون

در پایتون (و در این مطلب منظور پایتون ۳)، iterator شی است که دو متد به نام های __iter__ و __next__ را پیاده سازی می کنند. در حقیقت هر شی در پایتون که بخواهیم به عنوان یک iterator عمل کند، باید دو متد __iter__ و __next__ را پیاده سازی کند. متد __iter__ برای برگشت دادن یک شی از نوع iterator باید استفاده شود. در واقع متد __iter__ باعث ایجاد و مقدار دهی اولیه شدن یک شی از نوع iterator می شود. در مقابل متد __next__ عنصر بعدی شی iterator را برگشت می دهد. برگشت عنصر بعدی توسط متد __next__ تا زمانی ادامه می یابد که به انتهای itertor نرسیده باشیم و در صورتی که دیگر هیچ عنصری برای برگشت داده شدن وجود نداشته باشد، استثنا StopIteration برگشت داده می شود.

در واقع متد __next__ می داند که عنصر بعدی کدام است و همچنین می داند که آیا به انتهای iterator رسیده ایم یا نه؟ اما متد __iter__ یک نمونه از itertor را برگشت می دهد. در واقع در زمان ایجاد شی یا نمونه از itertor، متد __iter__ فراخوانی می شود ولی برای دسترسی به عناص، متد __next__ فراخوانی خواهد شد. قطعه کد زیر یک تاپل از عناصر را ایجاد می کند و سپس توسط تابع درونی ()iter یک iterator را از زوی آن ایجاد می کند و سپس توسط تابع درونی ()next به عنصر اول آن دسترسی پیدا می کند.

()iter تابع درونی (built-in) پایتون است که یک شی iterator را برگشت می دهد. ()iter دو آرگومان را به عنوان ورودی دریافت می کند. آرگومان اول نام یک شی (object) است که نوع آن بستگی به ارسال یا عدم ارسال آرگومان دوم دارد. آرگومان دوم اختیاری است و اگر تعیین نشود، پس آرگومان اول می تواند هر نوع مجموعه ای یا همان نوع متوالی (sequential) باشد. در صورتی که آر گومان دوم تعیین نشده باشد و نوع آرگومان دوم نیز غیر از نوع های متوالی مانند لیست ها، تاپل ها، دیشکنری ها و یا مجموعه ها (sets) باشد، استثنا TypeError نشان داده می شود.

در شکل بالا ابتدا یک تاپل ایجاد کرده ایم و سپس توسط تابع ()type نوع آنرا نشان داده ایم. در خط بعدی توسط تابع ()iter که نام متغیر tu1 (تاپل) را دریافت کرده، یک شی از نوع tuple_iterator ایجاد کرده ایم. در خطوط بعدی به ترتیب از تابع ()next برای دسترسی به عناصر درون شی iterator استفاده شده و نهایتا در اجرای چهارم تابع ()next چون شی it1 تنها سه عنصر داشت و دیگر عنصری برای نمایش و دسترسی وجود ندارد، پس استثنا StopIteration نشان داده می شود.

()next تابعی درونی (built-in) است که نام یک شی iterator را دریافت می کند و اولین عنصر و سپس با هر اجرا، عناصر بعدی شی iterator را برمی گرداند. در واقع تابع ()next از وضعیت شی iterator و اینکه کدام عنصرها برگشت داده شده اند و نهایتا آخرین عنصر موجود برای برگشت داده شدن کدام است، مطلع می باشد. در شکل بالا می بینید که چون شی it1 دارای سه عنصر است، پس چهارمین مرتبه اجرای تابع ()next منجر به استثنا StopIteration می شود.

کد زیر کلاسی به نام Counter را ایجاد می کند که در آن دو متد __iter__ و __next__ پیاده سازی شده اند. در خط ۲ تا ۴ تابع (یا متد) سازنده (یا constructor) کلاس Counter تعریف شده است. تابع سازنده دو مقدار low و high را دریافت و به ترتیب در self.current و self.high ذخیره می کند. در خط ۶ تا ۸، به دلیل پیاده سازی متد __iter__، زمانی که نمونه ای از کلاس Counter ایجاد می کنیم، این نمونه یا شی، به عنوان یک iterator در نظر گرفته می شود. در خط ۱۰ تا ۱۶ متد __next__ پیاده سازی می شود که به عناصر و عنصر بعدی دسترسی دارد. self.current در ابتدا به مقدار شروع و در گام های بعدی که یکی یکی به آن اضافه می شود، به مقدار فعلی اشاره دارد. self.high نیز مقدار نهایی یا پایانی را در خود دارد.

منبع کد

بنابراین مطابق شکل زیر می توانیم تابع ()next را بر روی شی یا نمونه ای از کلاس Counter اجرا کنیم تا با هر مرتبه اجرا، عنصری از مقدار ابتدایی low تا مقدار نهایی high نشان داده شوند.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *