همه ما برنامهنویسها میدانیم که حتی اگر به تمامی فوت و فنهای یک زبان مسلط نباشیم هم میتوانیم از پس توسعه برنامهها در آن زبان بربیاییم. بله! این یک واقعیت است، اما تمام واقعیت نیست. هرچند که اکثر ما برای نوشتن برنامههایمان از تمامی امکانات و مفاهیم یک زبان برنامهنویسی استفاده نمیکنیم (چه خواسته و چه ناخواسته)، اما دانستن یک سری از مفاهیم قطعا در توسعه بهتر و حرفهایتر نرمافزارهایمان به ما کمک خواهد کرد. این کمک میتواند در جهت ساده تر کردن کد، کوتاهتر کردن آن و یا حتی بهینه کردن آن باشد. تمامی زبانهای برنامه نویسی، به خصوص زبانهای سطح بالای جدید، علاوه بر مفاهیم پایه زبانها، سعی در ارائه مفاهیمی میکند که کار را برای برنامهنویس راحتتر کرده و دست برنامهنویس را برای پیاده سازی مفاهیم پیچیدهتر و به شکلی راحتتر، باز بگذارد. خوشبختانه پایتون دوستداشتنی نیز از این قاعده مستثنی نیست.
در این سری از نوشتهها، میخواهم به مفاهیمی در زبان برنامهنویسی پایتون بپردازم که شاید کمتر مورد توجه قرار گرفته باشد. امیداوارم این سری از مطالب برای افرادی که تازه شروع به یادگیری پایتون کردهاند و یا در میانه راه قرار دارند مفید باشد. این مطالب از این یک منبع خاص نیست. اما سعی میکنیم در طول نوشته، منابعی که به آنها رجوع کردهام را بیان کنم.
مفهوم Iterator در پایتون، از اون دسته از مفهوم هاست که احتمالا خیلی با اون کار کردیم اما دقیقا با اسم اون آشنایی نداریم.
در پایتون، Iteratorها، objectهایی هستند که میتوانید روی آنها Iterate انجام دهیم! احتمالا همه ما با این توضیح اول کار گیج میشیم! بیا دقیقتر به اون بپردازیم.
همونطور که احتمالا میدونی، همه چیز در پایتون object است (اگه نمیدونی، این مطلب شاید کمکت کنه، شاید بعدا در این باره نوشتم.) پس Iteratorها هم جدای از این حقیقت نیستند و ماهیت object دارند. پس تا اینجا بخش اول اون جمله پیچیده را تفکیک کردیم که خلاصه اون میشه : Iterator => Object. حالا بیا به بررسی قسمت دوم بپردازیم.
ما به چه کاری Iteration میگوییم؟ ترجمه فارسی این کلمه میشه تکرار پس به تکرار کردن میگوییم!
ما کجا در برنامهنویسی تکرار میکنیم؟ هر جایی که از حلقه به صورت مستقیم یا غیر مستقیم استفاده میکنیم.
پس در حلقهها ما Iteration انجام میدیم. (منبع)
در نهایت میتونیم بگیم Iteratorها اشیایی هستند که ما روی اونها در حلقهها تکرار انجام میدیم.
Iteratorها توی هر بار از تکرار حلقهی ما یکی از دادههایی را برمیگردونند که ما داریم روی اونا تکرار را انجام میدیم.
احتمالا اگه یک مقدار با پایتون آشنایی داشته باشی اولین چیزی که به ذهنت برای iterator رسیده، با توجه به تعاریف بالا، listها هستند. اما صبر کن! اول بیا یک مثال ببینیم.
این مثال ساده ترین مثالیه که میتونیم در مورد چاپ اعضای یک لیست بزنیم. همینطور که میبینی ما یک حلقه داریم و اعضای لیست test_list را یکی یکی چاپ میکنیم.
پس list یک Iterator است ؟ خیر!
علاوه بر مفهوم iterator در پایتون، مفهوم دیگهای به نام Iterable وجود داره و لیست یک نمونه از Iterableهاست.
اگه بخوایم ساده بگیم، Iterableها یک سری object هستند (که دیگه مشخص بود!) که میتونیم از روی اونا Iterator بسازیم.
چطوری؟ با استفاده از ()iter که یک فانکشن built-in در پایتون هست.
خروجی کد بالا
<class 'list'> <class 'list_iterator'> 1 2 3
همونطور که قبلا گفتیم، در پایتون این Iteratorها هستند که قابلیت این را دارند که بشود روی آنها تکرار انجام داد. اما سوال مهم اینه که پس چطور روی یک data type مثل list که iterable هست هم میشه حلقه for گذاشت؟
برای درک این نکته باید حلقه for مثال قبل را به شکل دیگهای نگاه کنیم (منبع) اما قبل از اون بیا کمی تخصصیتر در مورد Iterator و Iterableها بحث کنیم.
همونطور که گفتیم این دو مفهوم، ماهیت object دارند پس میتونند متدهای خاص پایتون که به شکل __example__ هستند را داشته باشند. اما وجود چه متدهایی در یک object ماهیت Iterator بودن به اون میده و چه متدهایی خاصیت Iterable بودن؟
اگه یک object متدهای __()iter__ و __()next__ را داشته باشه یعنی اون Iterator است. از طرف دیگه اگه یک object متد __()iter__ را فقط داشته باشه اون یک Iterable هست.
این وسط یک نکته هم بد نیست اشاره کنیم که میتونیم تمام متدهای یک کلاس را با فانکشن ()dir ببینیم.
اگه بخواهیم به صورت دستی روی یک Iterator تکرار انجام دهیم از فانکشن ()next استفاده میکنیم.
خروجی کد بالا
1 2 3
توجه بشه که قبل از اینکه یک iterable را با استفاده از فانکشن ()iter تبدیل به iterator کنیم، امکان استفاده از فانکشن ()next بر روی اون وجود ندارد. چون فانکشن ()next در حقیقت متد __()next__ را صدا میزنه و همونطور که گفتیم iterableها متد __()next__ را ندارند. الان متوجه میشیم که وقتی فانکشن ()iter را صدا میزنیم، در حقیقت متد __()iter__ صدا زده میشه.
الان میتونیم به این سوال پاسخ بدیم که در حقیقت در داخل حلقه for چه اتفاقی رخ میدهد؟
نکته قابل توضیح در مثال بالا اینه که وقتی فانکشن ()next به آخر iterator میرسه، StopIteration را raise میکند.
بله درسته! وقتی ما در پایتون روی یک Iterable مثل list حلقه for میذاریم، ابتدا این لیست به یک Iterator تبدیل میشه و تا جایی که StopIteration را raise کنه ادامه پیدا میکنه.
این بود مطلب من در مورد Iteratorهای جذاب داخل پایتون دوست داشتنی. شما خودتون هم میتونید iteratorهایی ایجاد کنید. کلاسی ایجاد کنید که متدهای __()iter__ و __()next__ را دارند و به همین راحتی iterator خودتون را ایجاد کنید.
بخش اول مجموعه مفاهیمی در پایتون که شاید نمیدانید که در مورد Iteratorها بود تمام شد.امیدوارم مفید بوده باشه. خوشحال میشم اگر سوالی داشتید بپرسید و اگر براتون مفید بود، با دوستاتون به اشتراک بذارید. برای اینکه ادامه این مجموعه را از دست ندید من را در ویرگول فالو کنید.
بخشهای دیگر این مجموعه
- مفاهیمی در پایتون که شاید نمیدانید - بخش دوم - Generators
با تشکر.