هنر برنامه نویسی با پایتون ، بخش هفتم: حلقه ها

برنامه ساده چاپ اعداد طبیعی کوچکتر از 4 را در نظر بگیرید ساده ترین راه نوشتن این برنامه ، تکرار  دستور Print برای هر یک از اعداد 0 تا 4 است تا به ترتیب با چاپ اعداد 3 ، 2 ، 1 ، 0 خواسته برنامه نویس برآورده گردد. اما اگر بخواهید برنامه چاپ اعداد طبیعی کوچکتر از 50 را به شیوه گفته شده بنویسید ، به ناچار باید برای چاپ هر یک از اعداد 0 تا 49 یک دستور  print() جداگانه بنویسید. و ناگفته پیداست که پنجاه بار تکرار دستور print  روشی غیر منطقی است چراکه این سبک از برنامه نویسی حجم برنامه را بی دلیل  افزایش داده و با کاهش خوانایی و سخت تر شدن درک کد ، ویرایش و اصلاح کد در آینده را دشوار می سازد. این دو مثال ساده نیاز به وجود سازوکاری برای برنامه نویسی ساده تر و روان تر کدهایی که باید بارها و بارها اجرا شوند را روشن می سازد.

 ضرورت وجود این سازوکار دوچندان می شود اگر بدانیم که در بسیاری از الگوریتم های حل مسائل دنیای واقعی نیاز به تکرار و اجرای چندباره کد ، گریزناپذیر است .یک مثال عملی از نیاز به تکرار کد ، محاسبه حقوق و دستمزد کارکنان است. چراکه نرم افزار ناچار به تکرار پردازش محاسبه حقوق و دستمزد برای هر یک از کارکنان به صورت جداگانه است. بنابراین با فرض اینکه تعداد کارکنان یک شرکت فرضی 2500 نفر باشد.  نرم افزار مجبور است اجرای سه قطعه کد : واکشی اطلاعات کارمند از فایل ورودی ، محاسبه حقوق و دستمزد و ذخیره نتیجه محاسبه در فایل خروجی را از اولین کارمند شروع و تا رسیدن به آخرین کارمند ادامه دهد. یعنی اجرای سه قطعه کد گفته شده 2500 بار تکرار می شود. این مثال نمونه ای از یک تکرار پایان پذیر است زیرا تکرار اجرای کد پس از تعداد اجرای مشخص و یا برقراری یک شرط پایان می پذیرد . در فرهنگ واژگان زبان های برنامه نویسی به تکرار ، حلقه (loop) گفته می شود.  مفهوم حلقه پایان پذیر در محاسبه حقوق و دستمزد کارکنان در تصویر زیر نمایش داده شده است : 

 

نوع دیگری از حلقه (loop) نیز وجود دارد که به آن حلقه بی نهایت گفته می شود چرا که اجرای کد پس از شروع ، هرگز پایان نخواهد یافت. حلقه بی نهایت بسیار ارزشمند است چرا که دربسیاری از  برنامه ها برای چیرگی بر چالشهای دنیای واقعی نیاز است تا یک دستور و یا گروهی از دستورات بی نهایت تکرار شوند برای نمونه رایانه خودرو(ECU) همواره در حال دریافت و پردازش اطلاعات رسیده از حسگر های نصب شده در بخش های گوناگون خودرو و ارسال دستور به اجزای اساسی خودرو است یعنی سه کد دریافت اطلاعات از حسگرها ( برای مثال حسگر اکسیژن) ، پردازش اطلاعات و ارسال دستور (برای مثال تنظیم دقیق ترکیب سوخت و هوا) به اجزای خودرو همیشه در حال تکرار است.  مفهوم حلقه بی نهایت یا پایان ناپذیر در تصویر زیر نمایش داده شده است :

در زبان برنامه نویسی پایتون دو دستور ویژه برای پردازش فعالیت های تکراری و پیاده سازی حلقه ها وجود دارد : یکی دستور for و دیگری دستور whileکه در فرهنگ واژگان برنامه نویسی بیشتر به نامهای حلقه for و حلقه while خوانده می شوند. این دو حلقه در ادامه درس با مثالهایی آموزش داده خواهند شد.

حلقه for  :

در زبان برنامه نویسی پایتون از حلقه for بیشتر برای پیمایش دنباله ای از عناصر  استفاده می شود از این رو به آن حلقه for in هم گفته می شود. لازم به یاد آوری است که بسیاری از انواع داده  موجود در پایتون نظیر رشته (string) ، range ، list ، tuple ، dict و set دنباله ای از عناصر هستند برای مثال نوع داده range که دنباله ای از اعداد است و یا نوع داده رشته(string) که دنباله ای از نویسه هاست . از این رو  محتوای آنها  با استفاده از حلقه for in به راحتی قابل پیمایش است. برای درک بهتر کدهای نوشته شده با حلقه for باید با دستور range() و عملگر in آشنایی کافی داشته باشید.

حالت کلی نگارش و الگوی بکارگیری حلقه  for به شکل زیر است :

for   Value   in Sequence :

       #  Loop Body

 

Value:  یک نام دلخواه برای متغیری است که در هر بار اجرای حلقه ، هر کدام از اعضای مجموعه sequence در آن قرار می گیرند.

Sequence : یک نوع داده قابل پیمایش است برای مثال یک متغیر رشته ای ، range ، list و ...

Loop Body : بدنه حلقه است که در هر  تکرار حلقه  پردازش می شود.

مثال : برنامه ای بنویسید که عددهای طبیعی کوچکتر از 50 را در خروجی صفحه نمایش چاپ کند.

برای درک بهتر مفهوم حلقه در این مثال ساده ، ابتدا الگوریتم آن را نوشته  و سپس روندنمای (FlowChart)   آن را  رسم می کنیم :

الگوریتم :

1- شروع

2- مقدار 0 را در متغیر i ذخیره کن

3- i  را چاپ کن

4- یک واحد به متغیر i  اضافه کن

5- اگر مقدار متغیر i کوچکتر از عدد 50 بود برو به گام سوم در غیر این صورت برو به گام ششم

6- پایان

 به گام پنجم دقت کنید تا زمانی که مقدار متغیر i کوچکتر از عدد 50 باشد گامهای سوم و چهارم تکرار خواهند شد به بیان دیگر بین گامهای سوم تا پنجم حلقه ای شکل گرفته که شرط خروج از آن این است که مقدار متغیر i بزرگتر یا مساوی عدد 50 باشد.

 این مفهوم در فلوچارت زیر به روشنی دیده می شود :

حال با دانسته هایی که از دستور range() ، عملگر in و الگوی بکارگیری حلقه for داریم  می توانیم برنامه نویسی این مثال را به روش زیر انجام دهیم :

for x in range(50):

    print(x)

 

ابتدا دستور range(50)  دنباله عددی 0 تا 49 را تولید می کند، سپس دستور for شروع به پیمایش این دنباله عددی می کند یعنی در ابتدا مقدار نخستین عنصر دنباله (عدد 0)  را در متغیر x ریخته و پس از آن دستور print(x) را اجرا می کند سپس مقدار دومین عدد دنباله (عدد 1) را در متغیر x ریخته و دوباره دستور print(x) را اجرا می کند . این تکرار با رسیدن به آخرین عنصر دنباله یعنی عدد 49  و چاپ آن ادامه می یابد. و سپس به پایان می رسد.

 

مثال : برنامه ای بنویسید که اعداد زوج دو رقمی را در خروجی صفحه نمایش چاپ کند.

الگوریتم حل :

1-شروع

2- عدد 10   را در متغیر i قرار بده

3- مقدار متغیر i را چاپ کن

4- مقدار متغیر i را 2 واحد افزایش بده

5- اگر مقدار متغیر i کوچکتر از 100 بود برو به گام سوم در غیر این صورت برو به گام ششم

6- پایان

 

برنامه نویسی مسئله با پایتون :

با توجه به دانسته های ما در مورد دستور range()  و عملگر  in می توان این حلقه را به صورت زیر نوشت :

for x in range(10, 100, 2):

     print(x)

 

مثال : برنامه ای بنویسید که یک نام خانوادگی را از کاربر گرفته و تک تک نویسه های موجود در آن را در خروجی صفحه نمایش چاپ کند.

می دانیم که هر رشته دنباله ای از یک یا چند  نویسه (character)است از این رو با استفاده از حلقه for می توان رشته مورد نظر را پیمایش کرد و با بهره گیری از عملگر in هر نویسه را به یک متغیر انتساب داد و سپس با استفاده از دستور print() آنرا در خروجی صفحه نمایش چاپ کرد. :

LastName=input("please enter your last name :")

for x in LastName:

    print(x)

مثال : برنامه ای بنویسید که اعداد بین 100 تا 500 که بر عدد 2 و یا بر عدد 9 بخش پذیر هستند را یافته و در خروجی صفحه نمایش چاپ کند :

یادآوری :  عددی بر 2 بخش پذیر است که باقی مانده تقسیم آن عدد بر 2 صفر باشد.

             عددی بر 9 بخش پذیر است که باقی مانده تقسیم آن عدد بر 9 صفر باشد.

for x in range)100, 501):

    if (x % 2) == 0 or (x % 9) == 0 :

        print(x)

مثال : برنامه ای بنویسید یک رشته را از ورودی گرفته و طول آنرا در خروجی صفحه نمایش چاپ کند.( طول یک رشته ، تعداد نویسه های موجود در آن رشته است.)

MyString=input("please enter one string :")

i=0

for char in MyString:

    i+=1

print(i)

 

مثال : برنامه ای بنویسید که مجموع اعداد 1 تا 1024 را جمع کرده و در خروجی صفحه نمایش چاپ کند.

sum = 0

for num in range(1, 1025):

    sum = sum + num

 

print(sum)

حلقه while  :

شکل کلی نگارش و الگوی بکار گیری این دستور به شکل زیر است :

 

While      حلقه  شرط

      بدنه حلقه  

با استفاده از حلقه while می توان کد مورد نظر را تا زمانی که شرط حلقه برقراراست یعنی نتیجه ارزیابی عبارت موجود در بخش شرط حلقه  دارای مقدار منطقی درست (true) است اجرا کرد. بدیهی است که با نادرست (false) شدن شرط ، حلقه while پایان می پذیرد.

   مثال : کد زیر اعداد طبیعی کوچتر از 50 را چاپ می کند

i=0

while(i < 50 ):

    print(i)

    i+=1

در برنامه بالا شرط کوچکتر بودن مقدار متغیر i از عدد 50  (i < 50) در ابتدای حلقه while بررسی می شود چنانچه شرط برقرار بود یعنی نتیجه ارزیابی عبارت مقایسه ای i < 50  مقدار منطقی درست (True) باشد دستور print(i) اجرا شده و به مقدار متغیر i یک واحد افزوده می شود و اجرای برنامه به ابتدای حلقه while برمی گردد یعنی تکرار بعدی آغاز شده و دوباره شرط  i < 50  بررسی می شود و این تکرار تا زمانی ادامه می یابد که  نتیجه ارزیابی شرط ابتدای حلقه  نادرست (False)  شود.

مثال : برنامه ای بنویسید که مجموع اعداد زوج دو رقمی را محاسبه و چاپ کند:

 sum = 0

i = 10

while (i < 100):

     sum += i

     i += 2

print(sum) # output is 2430

مثال : برنامه ای بنویسید که مجموع اعداد سه رقمی که همزمان بر 7 و 8  بخش پذیر هستند را محاسبه و چاپ کند.

یادآوری : اگر عدد A بر عدد B بخش پذیر باشد آنگاه باقی مانده تقسیم عدد A بر B برابر صفر است.

sum = 0

i = 100

while(i <= 999):

     if i % 7 == 0 and i % 8 == 0:

         sum += i

     i+=1

print(sum) # output is : 8512

 

حلقه های تودرتو :

گاهی ماهیت مسئله  چنان است که برای حل آن به ناچار باید از یک حلقه درون حلقه دیگراستفاده کرد یعنی حلقه دوم در بدنه حلقه نخست جای می گیرد و به ازای هر تکرار حلقه نخست ، تمامی تکرارهای حلقه دوم پردازش می شوند. به این حالت ، حلقه های تودرتو گفته می شود.به حلقه نخست حلقه بیرونی و به حلقه دوم حلقه درونی گفته می شود. برای مثال فرض کنید دو دنباله عددی A و B همانند زیر تعریف شده باشند ، می خواهیم برنامه ای بنویسیم که حاصل ضرب هریک از اعداد موجود در دنباله A در هر یک از اعداد موجود در دنباله B را محاسبه و چاپ کند:

A=5, 6, 7, 8

B=4, 5, 6, 7

 برای این کار به دو حلقه نیاز داریم ، حلقه نخست عناصر موجود در دنباله A را پیمایش می کند و حلقه دوم عناصرموجود در دنباله B را پیمایش خواهد کرد اما با توجه به اینکه هر یک از اعداد موجود در دنباله A  باید در تک تک اعداد موجود در دنباله B ضرب شوند از این رو نیاز است تا به ازای هر عنصر موجود در A تمامی عناصر موجود در B پیمایش شوند و این یعنی حلقه پیمایش کننده عناصر B باید در بدنه حلقه پیمایش کننده عناصر A جای گیرد:

A=range(5,9,1)

B=range(4,8,1)

for x in A:

      for y in B:

            print(x*y)

برنامه بالا را می توان با حلقه while و به شکل زیر بازنویسی کرد:

x=5

y=4

while(x < 9):

      while(y < 8):

            print(x*y)

            y += 1

      y = 4

      x += 1

مثال : برنامه ای بنویسید که شکل هندسی زیر را با چاپ نویسه ستاره ( * ) تولید کند.

*

**

***

****

*****

******

*******

********

*********

**********

***********

************

همانگونه که دیده می شود ستاره ها در 12 سطر پشت سرهم قرار گرفته اند و در هر سطر ، تعداد ستاره های چاپ شده برابر با شماره سطر است یعنی در سطر اول یک ستاره ، در سطر دوم دو ستاره و به همین ترتیب ادامه می یابد تا سرانجام در آخرین سطر 12 ستاره چاپ می شود. بنابراین نیاز به وجود دو حلقه است ، حلقه اول دنباله عددی 1 تا 12 را پیمایش می کند که به معنای پیمایش سطر نخست تا آخرین سطر است ، و حلقه دوم به ازای هر تکرار حلقه اول  و به تعداد شماره سطر دستور print("*") را اجرا می کند :

 

x=1

while(x < 13):

      y = 1

      while(y < x + 1):

            print("*", end="   ")

            y += 1

      print("\n")

      x += 1

 

نکته : دستور print() پس از چاپ ورودی خود به صورت خودکار به سطر بعدی می رود برای جلوگیری از این رفتار پیش فرض یک ورودی جدید به نام end و با مقدار فضای خالی (" ") به این دستور داده می شود تا پس از چاپ هر ستاره در سطر جاری بماند و تمامی ستاره های موجود در سطر فعلی در همان سطر چاپ و با یک فاصله خالی از هم جدا شوند.

نکته : print("\n") یعنی به سطر بعدی برو ، در حقیقت نویسه \n  بیانگر کد اسکی سطر جدید است.

 

مثال :  برنامه ای بنویسید که دو رشته را از کاربر گرفته وتعداد تکرار هر نویسه موجود در رشته اول  را در رشته دوم یافته وچاپ کند.

str1 = input("Pleas enter string1:")

str2 = input("Pleas enter string2:")

count = 0

for x in str1:

    for y in str2:

        if x==y:

            count +=1

           

    print(x,"   ", count)

    count =0

یک نمونه از خروجی این برنامه در زیر آمده است :

 

Pleas enter string1:arash

Pleas enter string2:arman

a     2

r     1

a     2

s     0

h     0

 

 دستور break :

به هنکام خرید ازیک فروشگاه بزرگ دیده اید که صندوقدار فروشگاه با استفاده از ابزاری به نام بارکدخوان ،شناسه یکتای کالای خریداری شده را به نرم افزار وارد می کندو نرم افزار با جستجو و پیمایش فهرست قیمت صدها و گاهی هزاران کالای موجود در فروشگاه که از پیش در پایگاه داده نرم افزار ثبت شده اند، قیمت کالای خریداری شده توسط مشتری را یافته و برای پردازش(محاسبه قیمت کل ، اعمال تخفیف ، تنظیم فاکتور و ...) در اختیار کد موجود در نرم افزار قرار می دهد با فرض اینکه فروشگاه فرضی مادارای تعداد 4000 کالای گوناگون باشد و فهرست شناسه تمامی آنها به صورت نامرتب در پایگاه داده نرم افزار ثبت شده باشد برای جستجوی یک شناسه کالای خاص در این فهرست نیاز به اجرای حلقه ای با 4000 بار تکرار است حال فرض کنید شناسه کالای ما در مکان 500 فهرست ، ذخیره شده است بنابراین در تکرار پانصدام، نرم افزار کد کالای مورد نظر را یافته و قیمت آن را بدست می آورد. به صورت منطقی پس از این دیگر لازم نیست جستجو ادامه یابد و حلقه باید پایان پذیرد اما می دانیم که در حالت عادی اجرای یک حلقهfor  زمانی پایان می یابد که پیمایش فهرست به آخرین عنصر موجود در آن برسد و اجرای یک حلقه while نیز زمانی پایان خواهد یافت که نتیجه ارزیابی شرط ابتدای حلقه مقدار منطقی نادرست (false) باشد. ازاین رو در مثال بالا بدون وجود راهی برای خروج زود هنگام از حلقه تعداد 3500 تکرار دیگر نیز اجرا خواهند شد بدون آنکه به اجرای آنها نیازی باشد.اهمیت وجود راهی برای خروج زود هنگام از یک حلقه زمانی روشن تر خواهد شد که بدانیم اجرای بیش از نیاز یک حلقه به معنای مصرف منابع باارزشی چون زمان پردازشگر(CPU)وفضای حافظه اصلی(RAM) رایانه است که خود موجب کندی نرم افزار و کاهش سرعت پاسخگویی به درخواست کاربران از سوی برنامه می شود.

در زبان برنامه نویسی پایتون دستور break موجب خروج زودهنگام از حلقه می شود.  مفسر پایتون با رسیدن اجرای کد برنامه به دستور break اجرای  حلقه را متوقف می کند و با خارج شدن از حلقه دستور پس از حلقه را اجرا می کند. لازم به یادآوری است که در حلقه های تودرتو وجود دستور break در بدنه حلقه درونی ، تنها موجب خروج از حلقه درونی خواهد شد.

 

مثال : برنامه زیر اعداد 1 ، 2 ، 3  را در خروجی

i=1

while i < 6:

    print(i)

    if i == 3:

        break

    i += 1

 

همان مثال با حلقه for :

for i in range(1,7,1):

    print(i)

    if i == 3:

        break

دستور continue  :

 این دستور برخلاف دستور break که به اجرای یک حلقه پایان می دهد تنها تکرار فعلی حلقه را پایان داده و اجرا را از تکرار بعدی حلقه از سر می گیرد.

مثال : قطعه کد زیر تنها اعداد فرد موجود در دنباله عددی 1 تا 20 را چاپ می کند

for x in range(1,21,1):

       if x % 2 == 0:

            continue

       print(x)

مثال : قطعه کد زیر اعداد 9 تا 0 را چاپ خواهد کرد اما عدد 5 چاپ نخواهد شد

x = 10                   

while x > 0:             

     x = x -1

     if x == 5:

          continue

     print (x)

 پایان بخش هفتم

محمد ایزانلو

خرداد 1401 هجری خورشیدی

نظرات 0 + ارسال نظر
امکان ثبت نظر جدید برای این مطلب وجود ندارد.