حلقه های تکرار for و while در زبان برنامه نویسی پایتون
مقاله قبلی: ساختار های تصمیم گیری پایتون if…else
یک زبان برنامه نویسی دارای یک سری متغیر، ساختارهای تصمیم گیری و تکرار و توابع ورودی و خروجی است.
فارغ از این که با چه زبانی برنامه نویسی می کنید خیلی اوقات نیاز دارید که یک یا مجموعه ای از دستورات را به دفعات مشخص یا تا زمانی که یک شرط خاص برقرار است اجرا کنید این جاست که نوعی از ساختارهای کنترلی یعنی ساختارهای تکرار به کارتان می آید. نمودار زیر، نحوه عملکرد یک حلقه تکرار را نشان می دهد.
در پایتون نیز دو نوع حلقه تکرار داریم حلقه for و while . توسط این دو حلقه، می توان یک کار تکراری را به تعداد مشخص انجام داد مثلا در کد زیر می بینید که توسط حلقه for تمام اعداد اول موجود در لیست primes را پیمایش و چاپ نموده ایم.
حلقه for
در حلقه های for می توانیم به ازای هر یک از آیتم های موجود در یک لیست، تاپل، مجموعه و …، دسته ای از دستورات را اجرا کنیم. مثلا در قطعه کد زیر به جای این که سه بار دستور print را بنویسیم، این دستور را در داخل حلقه تکرار for قرار می دهیم و به کمک یک شمارنده که لیست ما را پیمایش می کند هر بار یکی از میوه های موجود در لیست fruitsرا انتخاب کرده و به وسیله تابع print آن را چاپ می کنیم.
اهمیت حلقه for زمانی آشکار می شود که لیست مورد نظر ما دارای تعداد زیادی عنصر باشد. مثلا اگر لیست fruits به جای سه عنصر دارای عناصر بیشتری بود در این صورت استخراج تک تک این عناصر به روش معمول کاری بسیار طاقت فرسا می شد حال آن که به کمک حلقه for این کار در سریع ترین زمان ممکن و با بهینه ترین میزان کد نویسی میسر گردید.
از حلقه for می توان برای چاپ تک تک حروف یک رشته هم استفاده کرد.
کاربرد تابع range() در حلقه for
حال اگر بخواهیم حلقه تکرار به تعداد دفعاتی که ما برایش مشخص می کنیم اجرا شود می توانیم از تابع range() استفاده کنیم. در این صورت دستورات داخل حلقه به تعداد دفعاتی که توسط تابع range() مشخص می شود انجام می گیرد.
این تابع مجموعه ای از اعداد متوالی را بر می گرداند که از صفر شروع شده، با یکدیگر یک واحد اختلاف دارند و با رسیدن با عدد مشخص شده پایان می یابند. مثلا range(6) به جای اعداد 0 تا 6 ، اعداد 0 تا 5 را بر می گرداند.
شما می توانید نقطه شروع و پایان این تابع را خودتان هم مشخص کنید مثلا range(3,6) اعداد 3 تا 6 (و نه خود 6) را بر می گرداند.
در مثال زیر نیز به کمک حلقه for توانستیم اعداد 1 تا 10 و توان 2 آنها را محاسبه کرده ایم:
در تابع range()، گام افزایش به طور پیش فرض یک واحد می باشد اما جالب است بدانید که در شکل سوم این تابع شما می توانید علاوه بر مشخص کردن نقطه شروع و پایان، گام افزایشی دلخواه خود را نیز بنویسید. مثلا در قطعه کد زیر، می بینید که گام افزایش، به جای یک واحد، 8 واحد است.
در مقاله آموزشی لیست های پایتون نیز به تشریح کامل نحوه کارکرد این تابع پرداخته ایم. در مثال زیر هر سه شکل تابع range() آورده شده است:
حلقه while
این نوع حلقه نیز یک عمل تکراری را تا زمانی که یک شرط بولی برقرار باشد انجام می دهد و تفاوتی که با حلقه for دارد این است که در حلقه while شرط حلقه، قبل از اجرای دستورات حلقه بررسی می شود.
یک مثال کاربردی از حلقه while
برای محاسبه فاکتوریل یک عدد هم می شود از این حلقه استفاده کرد. مثلا در قطعه کد، حلقه while ی را مشاهده می کنید که فاکتوریل عدد 10 را چاپ می کند. شما می توانید همین برنامه کوچک را با توابع ورودی که بعدها خواهید آموخت گسترش دهید و برنامه ای بنویسید که از کاربر عددی را دریافت کرده و هم چون یک ماشین حساب، فاکتوریل آن را محاسبه کند.
حلقه بی نهایت (Infinite Loop)
اگر شرط یک حلقه تکرار هیچ گاه False نشود آن گاه به آن، یک حلقه بی نهایت گفته می شود چرا که دستورات داخل حلقه بی نهایت بار اجرا می شوند. بنابراین هنگامی که یک حلقه while می نویسید باید حواستان به پایان پذیر بودن شرط حلقه باشد. البته ممکن است در برنامه نویسی کلاینت / سرور این گونه حلقه ها مفید باشند مثلا در جایی که سرور باید همیشه اجرا شود تا برنامه کلاینت بتواند با آن ارتباط برقرار کند.
در قطعه کد زیر نمونه ای از یک حلقه بی نهایت را می بینید ملاحظه می کنید که دستورات این حلقه بی نهایت بار تکرار می شوند مگر این که شما به جای یک عدد به اشتباه چیز دیگری را تایپ کنید یا کلیدهای ترکیبی ctrl +c را فشار دهید تا اجرای این حلقه متوقف شود.
مشابه ساختار تصمیم گیری if، اگر بدنه حلقه while هم تنها دارای یک دستور باشد می توانید آن را در همان خط هدر (while) بنویسید.
دستور break
در ساختارهای تکرار هم گاهی اوقات لازم می شود که وقتی شرطی برقرار شد تکرار دستورات متوقف شود . در چنین مواردی، دستور break نیاز ما را برآورده کرده و به محض برقراری شرط مورد نظر، باعث توقف تکرار دستورات حلقه (به ازای آیتم های باقیمانده) و در نهایت خروج کامل از حلقه می شود.
مثلا همان طور که در مثال زیر می بینید وقتی شرط برقرار می شود (شمارنده حلقه به آیتم “banana” می رسد) برنامه از حلقه خارج شده و دیگر دستور print حلقه برای آیتم بعدی یعنی “cherry” اجرا نمی شود.
در مثال بالا می توانیم با یک جابه جایی کاری کنیم که برای آیتمی که به ازای آن شرط برقرار شده هم دستورات حلقه متوقف شود. بدین منظور باید شرط مورد نظر و دستور break را قبل از دستور print بنویسیم. می بینید که خروجی این دو کد یکسان نخواهند بود و دیگر خود آیتم “banana” هم چاپ نمی شود.
یک برنامه کوچک و کاربردی با استفاده از break
در این برنامه، از کاربر خواسته می شود که عددی را وارد کند سپس این عدد در یک لیست از قبل تعریف شده مورد جستجو قرار می گیرد و در صورتی که در لیست موردنظر وجود داشت پیغام “پیدا شدن در لیست” چاپ شده و برنامه از حلقه خارج می شود و در غیر این صورت پیغام “پیدا نشدن در لیست” چاپ می شود.
دستور continue
در پایتون هم مشابه زبان های برنامه نویسی دیگر مثل سی و سی پلاس، دستوری به نام continue داریم که از اجرای دستورات حلقه به ازای آیتم جاری (آیتمی که به ازای آن شرط برقرار شده) ممانعت کرده و باعث پرش به گام بعدی حلقه های for و while می شود.
مثلا در قطعه کد زیر می بینید که وقتی شمارنده حلقه به آیتم “banana” میرسد اجرای دستور حلقه (print) را به ازای این آیتم متوقف کرده و شمارنده به سراغ عناصر بعدی حلقه رفته و دستورات حلقه را برای آن ها ادامه می دهد.
در قطعه کد زیر نیز طریقه استفاده از دستور break و continue مجددا در قالب مثالی تشریح شده است.
نکته : اگر چندین حلقه تو در تو داشته باشیم و وقتی اجرای برنامه به دستور break حلقه درونی تر برسد، اجرای حلقه درونی تر متوقف شده و دستور بعدی حلقه درونی تر اجرا می شود.
حلقه های تو در تو
همان طور که در پایتون می توان ساختارهای تصمیم گیری تو در تو ایجاد نمود با قرار دادن یک حلقه تکرار در درون حلقه تکرار دیگر، می توان ساختارهای تکرار تو در تو نیز ایجاد کرد. هم چنین شما می توانید در داخل یک حلقه تکرار هر نوع حلقه تکراری را بگنجانید. مثلا در داخل یک حلقه for یک حلقه whileقرار دهید و یا بالعکس.
در حلقه های تو در تو به ازای هر بار تکرار حلقه بیرونی، حلقه درونی به طور کامل اجرا می شود. مثلا فرض کنید دو لیست داریم که یکی شامل نام سه رنگ و دیگری شامل نام سه میوه است. حال اگر بخواهیم نام هر میوه را با هر سه رنگ موجود چاپ کنیم برای تولید کد بهینه، بهتر است که از دو حلقه تو در تو استفاده کنیم. در قطعه کد زیر به ازای هر بار اجرای حلقه پیمایش کننده لیست رنگ ها، حلقه پیمایش کننده لیست میوه ها به طور کامل اجرا می شود. مثلا وقتی x=”red” است y مقادیر “apple” ، “banana” و “cherry” را اتخاذ می کند و به دنبال آن دستور print اجرا می شود.
به عنوان مثالی دیگر از حلقه های تو در تو، می توان تولید جدول ضرب اعداد 1 تا 10 را با استفاده از دو حلقه تو در توی for نام برد. ملاحظه می کنید که با هر بار اتمام حلقه درونی تر، تابع print() اجرا شده و بین هر 10 آیتم یک خط فاصله می اندازد.
کاربرد کلمه کلیدی else در حلقه های تکرار
در پایتون می توانید دستور else را با حلقه های تکرار ترکیب کنید.
- با به کار بردن کلمه کلیدی else در حلقه for می توانیم مشخص کنیم که در صورت اتمام عادی حلقه (نه با دستور break)، چه کدی اجرا شود.
بدین منظور باید کدهای مورد نظرمان را درون بلاک else قرار دهیم. مثلا در قطعه کد زیر، با اتمام حلقه for (چاپ اعداد 0 و 1 و 2 و 3 و 4 و 5)، عبارت “! Finally finished ” چاپ می شود.
اما در قطعه کد زیر می بینید که بدلیل خروج از حلقه با دستور break ، دستورات بلاک else اصلا اجرا نمی شوند.
- یا در حلقه while می توانیم با استفاده از این دستور مشخص کنیم که در صورت False شدن شرط حلقه چه کدی اجرا شود.
Iterable و Iterator در پایتون چیست؟
تاکنون با Iterable های مختلفی آشنا شدید که شاید آن ها را تنها با نام ساختارهای داده ای می شناختید. درحقیقت به هر چیزی که بتوان توسط یک حلقه for اعضای آن را پیمایش نمود و برگشت داد می توان نام Iterable را اطلاق کرد. همانند لیست ها، رشته ها، تاپل ها و …
Iterator هم شیئی است که می توان توسط متدهای آن، همانند یک حلقه for، در بین اعضای یک مجموعه از داده ها یا Iterable ها حرکت کرده و اعضای آن ها را یکی یکی برگرداند. در پایتون یک شی Iterator توسط دو متد next() و iter() پیاده سازی می شود. در مجموع به این دو متد iterator protocol گفته می شود.
تابع iter() یک شی Iterator را ایجاد می کند. به عبارت دیگر، با اعمال تابع iter() بر روی یک تکرار شونده(Iterable )، یک تکرار کننده (Iterator) ایجاد می شود تابع next() نیز یک تکرار کننده را به عنوان آرگومان دریافت کرده و بین اعضای آن حرکت کرده و در هر لحظه یکی از اعضای متوالی آن را بر می گرداند. این تابع وقتی به انتهای یک تکرار کننده می رسد و داده ای را برای برگشت دادن نمی یابد استثنا یا همان خطای StopIteration را تولید می کند.
هم چنین شما می توانید به جای تابع iter() از متد__iter__() و به جای تابع next() از متد __next__() نیز استفاده کنید نتیجه یکی است. به مثال زیر توجه کنید تا به صورت عملی با نحوه کار این توابع آشنا شوید :
در مثال زیر تکرار شونده ما همان لیست my_list است که آن را به عنوان آرگومان برای تابع iter() ارسال کرده ایم تا شی تکرار کننده ای به نام my_iter ایجاد شود. حال خود این تکرار کننده را نیز به عنوان آرگومان برای تابع next() ارسال کرده ایم تا عناصر متوالی این تکرار کننده را برگرداند. ملاحظه می کنید که آیتم های 4 و 7 لیست را توسط تابع next() و آیتم های 0 و 3 را توسط متد __next__() برگردانده و چاپ کرده ایم. در مرحله بعد وقتی مجددا تابع next() را صدا می زنیم چون این تابع، به انتهای این تکرار کننده رسیده است و آیتمی را برای برگرداندن نمی یابد خطای StopIteration را بر می گرداند.
در حقیقت مکانیزم بالا، معادل همان حلقه for عادی است که به طور خودکار عناصر آن لیست را پیمایش می کند. می بینید که خروجی این دو قطعه کد عین هم است.
حال اگر بخواهید که اعضای یک لیست را توسط مبحث iteration به صورت خودکار چاپ کنید می توانید آن را توسط یک حلقه while و مکانیزم مدیریت خطا به شکل زیر پیاده سازی کنید.
می بینید که در قطعه کد بالا پس از مقداردهی یک لیست و ایجاد شی it_obj توسط تابع iter() ، از یک حلقه while استفاده کرده ایم و در داخل این حلقه، عبارت print(next(it_obj)) را که در آن احتمال بروز خطای StopIteration وجود دارد درون بلاک try قرار داده ایم. در نتیجه این دستور تا زمانی تکرار می شود که با خطای StopIteration مواجه شود و بعد از بروز این خطا کنترل اجرای برنامه از حلقه while خارج می شود و بدین ترتیب می توانیم تمامی عناصر لیست my_list را به طور خودکار در خروجی چاپ کنیم.
مقاله بعدی: توابع ورودی و خروجی پایتون
ترجمه: رقیه آقایاری
نظر شما چیست؟
پرسش های خود را در بخش پرسش و پاسخ مطرح کنید