کتاب عصر پایتون/فصل چهارم: ساختارهای کنترلی

ساختارهای کنترلی

ویرایش

همانطور که دانستیم برنامۀ کامپیوتری متشکل از دنباله‌ای از دستورالعمل‌ها است؛ که توسط برنامه‌نویس برای انجام عملیات خاصی نوشته می‌شود. در هر برنامه با توجه به هدف یا ساختمان داده‌ای که می‌خواهیم به‌دست آوریم و یا اهدافی که باید به آن‌ها دست یابیم؛ باید روند اجرای دستورات را کنترل کنیم. یعنی برخی از آنها را در شرایطی خاص اجرا کرده یا نکنیم و یا حتی برخی از آن‌ها را تکرار نماییم.

به همین دلیل برنامۀ ما به قطعه‌کدهایی تقسیم می‌شود که اجرای آن‌ها را توسط ساختارهای کنترلی تنظیم می‌کنیم.

دو ساختار کنترلی عمده در برنامه‌نویسی وجود دارد:

۱. شرط یا تصمیم‌گیری -> منطق و شرط

۲. حلقه یا اصطلاحاً تکرار -> حلقه

قطعه‌کد چیست

ویرایش

قطعه‌کد قسمتی از برنامه است که روند اجرای آن به‌صورت طبیعی و پشت سر هم نباشد. استفاده از حلقه و تابع در زبان سطح پایین موجب به‌وجود آمدن قطعه‌كد شده است که از نظر قدمت تقریباً همپای برنامه‌نویسی كامپیوتر است. برای مثال یک قطعه‌کد فقط در زمانی که شرط خاصی برقرار باشد اجرا می‌شود یا قطعه‌ای از کد به دفعات زیاد و پشت‌سرهم و به تعداد از پیش تعیین شده‌ای تکرار می‌گردد. برای نشان دادن قطعه‌کد از نشانه‌ایی استفاده می‌شود که محل شروع و اتمام کد را نشان می‌دهد. برای مثال استفاده از عباراتی چون begin و end در زبان‌هایی چون پاسکال یا دلفی نشان‌دهندۀ محل شروع و خاتمۀ یک قطعه کد است. یا در زبان قوی و محبوب C از اکولاد باز (}) به‌عنوان شروع‌کنندۀ قطعه کد و از اکولاد بسته ({) به عنوان پایان‌دهندۀ یک قطعه کد استفاده می‌شود و کدی که مابین این دو باشد درون قطعه کد و جدا از روند اصلی برنامه محسوب می‌شود.

قطعه‌کد در پایتون

ویرایش

برخلاف زبان‌های دیگر مانند C و Pascal که از علائم و عباراتی چون {} ، begin و end برای نمایش شروع و پایان یک قطعه‌کد استفده می‌کنند؛ پایتون علامت یا عبارت خاصی برای این منظور ندارد! برای مشخص کردن محدودۀ یک قطعه کد (مثلاً تابع، دستورات شرطی، حلقه، کلاس و ... ) از فاصله‌گذاری اول دستورات استفاده می‌شود. به این صورت که پس از خطی که بقیۀ دستورات زیرمجموعۀ آن هستند، به‌اندازۀ دلخواه فاصله یا تورفتگی داده می‌شود این فاصله‌های یکسان تا زمانی ادامه می‌یابد که محدودۀ دستور پایان یابد. این روش باعث کاهش مقدار کد برنامه و خوانایی بیشتر برنامه می‌شود.

از این روش در حالت معمول و برای خوانایی در زبان‌های دیگر نیز استفاده می‌شود. اکثر برنامه‌نویسان از تورفتگی کد برای افزایش خوانایی برنامه‌هایشان استفاده می‌کنند. پایتون با استفاده از این قابلیت هم مشکل نشان‌گذاری قطعه‌کدها را رفع کرده و هم الزامی برای رعایت این نظم و روند خاص برنامه‌‌نویسی ایجاد کرده است. به این ترتیب کدها و برنامه‌های پایتون تقریباً استاندارد هستند و ظاهر یکسانی دارند.

برای مثال به این کد دقت کنید. این کد، ظاهر و منطق کلی دستور شرطی if در پایتون را نشان می‌دهد.

>>> name = 'python'
>>> lang = 'python'
>>> if lang == 'python':
...     print 'You Are in right way !'
...
You Are in right way !

این یک مثال درست از قطعه‌کد است. دستور چاپ دارای تورفتگی نسبت به دستور شرط می‌باشد. پس این دستور زیرمجموعه‌ای از شرط است و در صورت درست بودن آن اجرا خواهد شد. اگر عبارت شرط حاوی دستورات بیشتری بود همۀ آن‌ها باید درست زیر دستور چاپ نوشته می‌شدند. در غیر این صورت برنامه اجرا نشده و پیغام خطایی ظاهر می‌شد. پس از پایان قطعه‌کد باید دقیقاً به زیر محل آغاز قطعه‌کد (در اینجا if) برگردید و ادامۀ برنامه را دقیقاً از زیر دستور شروع قطعه‌کد ادامه بدهید.

در مثال بعدی یکی از دستورات داخل قطعۀ شرط (خط سوم) با دستور قبلی خود به اندازۀ یک فضای خالی فاصله دارد. برنامه اجرا نشده و با نمایش پیغامی محل وقوع خطا و نوع آن نمایش داده می‌شود.

>>> if lang == 'python':
...     print 'You Are in right way !'
...   print 'go on'
File "<stdin>", line 3
    print 'go on'
            ^
IndentationError: unindent does not match any outer indentation level

پس اگر حتی دستور ساده‌ای چون دستور چاپ (print) را با فاصله (حتی یک فضای خالی) از سمت چپ بنویسید برنامه اجرا نخواهد شد. شاید رعایت این سبک خاص و منحصربه‌فرد در ابتدا کمی سخت و تا حدودی مضحک بنظر آید اما این یکی از مهم‌ترین ویژگی‌های پایتون است که زیبایی خاصی به کدهای نوشته شده می‌دهد و برنامه‌نویسی را لذت‌بخش و راحت می‌کند.

منطق و شرط

ویرایش

شرط در واقع ساختاری است که اجازۀ اجرای قطعه‌کدی را به ازای کنترل یک عبارت منطقی می‌دهد. در پایتون شرط ساده با عبارت if مشخص شده و به‌صورت زیر اعمال می‌‌شود:

if logicalVariable:
    Code Block

متغیر منطقی چیست؟

ویرایش

متغیرهای منطقی (Logical Variables) می‌توانند حامل یکی از دو مقدار درست یا غلط باشند. تصمیم‌گیری نیز بر همین اساس صورت می‌گیرد یعنی اگر این متغیر حامل مقدار درست باشد شرط، قطعه‌کد مربوطه را به اجرا در می‌آورد. از دید دیگر این متغیر ساده‌ترین نوع یک عبارت منطقی است. عبارت‌های منطقی را به‌طور مختصر می‌توان به دو دسته ساده و پیچیده تقسیم کرد. همۀ عبارت‌های منطقی به یکی از مقادیر درست یا غلط ختم می‌شوند. این عبارات با مقادیر و عملگرهای منطقی ساخته می‌شوند که همگی دودویی هستند یعنی برای انجام عمل به دو عملوند احتیاج دارند. عملگرهای منطقی ابتدایی از این قرارند:

عملگر های منطقی عملگر توضیح
== برابری دو عملوند
=! نابرابری دو عملوند
< بزرگتر
> کوچکتر
=< بزرگتر یا مساوی
=> کوچکتر یا مساوی
and و منطقی
or یا منطقی
not متمم (not)

ساخت عبارات منطقی

ویرایش

در بالا در مورد چگونگی شکل‌گیری عبارات مختصر گفته شد. در اصل مقادیر منطقی اولیه با عملگرهای منطقی که در متن بالا به‌شکل کم‌رنگ نوشته شده‌اند به‌وجود آمده و با دو عملگر پررنگتر یعنی and و or ترکیب خواهند شد. مقایسۀ برابری: ==

عمل مقایسۀ دو شیء (متغیر، عدد، رشته یا ... ) توسط دو علامت مساویِ به‌هم‌چسبیده صورت می‌گیرد. علامت مساوی تنها، عمل نسبت دادن یک مقدار به متغییر را انجام می‌دهد. پس هنگام مقداردهی یا مقایسه دقت داشته باشید که این دو را به‌جای هم به‌کار نبرید . حاصل نتیجه تست برابر بودن دو مقدار مقدارهای درست (True) یا نادرست (False) خواهد بود.

>>> 1 == 1
True
>>> 1 == 2
False

زمانی که شما از عملگر مقایسۀ برابری (==) برای دو عبارت استفاده می‌کنید، مفسر پایتون مقادیر دو طرف عملگر (عملوندها) را با یکدیگر مقایسه می‌کند. اگر دو مقدار برابر نباشند مقدار نادرست یا False و در صورت برابری مقدار درست یا True برگشت داده می‌شود. در صورتی که شما از انواع مختلف اعداد استفاده کنید عمل تبدیل نوع خودکار نیز انجام می‌پذیرد.

>>> 1.23 == 1
False
>>> 1.0 == 1
True

از عملگر مقایسه می‌توان برای مقایسۀ اکثر انواع دادۀ پایتون استفاده کرد. در درس‌های آینده با نحوۀ سربارگزاری عملگرها و در نتیجه ایجاد روش‌های مقایسه منحصربه‌فرد برای هر شیء یا کلاس آشنا خواهید شد. برای مقایسۀ لیست مفسر پایتون تک تک عناصر لیست را از نظر مقدار و محل با یکدیگر بررسی می‌کند. اگر دو لیست اعضایی یکسان ولی با ترتیب غیریکسان داشته باشند با یکدیگر برابر نیستند.

>>> city = ["Tabriz", "Tehran", "Shiraz", "Yazd"]
>>> city2 = ["Yazd", "Shiraz", "Tabriz", "Tehran"]
>>> city == city2
False
>>> city2 = ["Tabriz", "Tehran", "Shiraz", "Yazd"]
>>> city == city2
True

مقایسۀ داده‌هایی از نوع دیکشنری نیز امکان‌پذیر است. در این صورت محل داده‌ها در نتیجۀ مقایسه تأثیری نخواهد داشت و فقط به ازای هر کلید و مقدار باید دقیقا همان داده‌ها در دیکشنری دیگر موجود باشد. مقایسه نابرابری: =!

عمل مقایسۀ نابرابری در حقیقت متمم یا منفی شدۀ مقایسۀ برابری است. به این ترتیب که اگر طرفین عملگر نابرابری، برابر باشند مقدار نادرست و در غیر این صورت مقدار درست برگشت داده می‌شود.

>>> 3 == 3
True
>>> 3 != 3
False
>>> 5 != 4
True

فاصله‌گذاشتن بین نماد =! و یا برعکس نوشتن آن، (به صورت !=) یک خطای منطقی محسوب می‌شود. و در زمان اجرا تأثیرگذار خواهد بود. مقایسۀ بزرگتری و کوچکتری: < و >

پایتون برای مقایسۀ دو عبارت از لحاظ مقدار از علامت‌های برگرفته شده از ریاضیات استفاده می‌کند. شما قبلاً نیز با این علایم آشنایی دارید.

>>> 5 < 3
False
>>> 10 > 2
True

با استفاده از عملگرهای مقایسه‌ای امکان مقایسۀ دو رشته نیز وجود دارد. مقایسه و ارزش کاراکترها بر حسب توالی و ترتیب کاراکترها است. کم‌ارزش‌ترین کاراکتر حرف بزرگ “A” است. و بقیۀ کاراکترهای حروف بزرگ از حرف “A” بزرگتر هستند و “Z” از بقیۀ حروف بزرگ زبان انگلیسی ارزش بیشتری دارد. حروف کوچک انگلیسی ارزش بیشتری نسبت به حروف بزرگ دارند. یعنی کاراکتر “a” از همه کاراکترهای بزرگ با ارزش‌تر است. مبنای این ترتیب در واقع کدهای اسکی کاراکترها هستند. پس “z” باارزش‌ترین و “A” کم‌ارزش‌ترین کاراکتر موجود در الفبای انگلیسی است.

>>> a > b
False
>>> A > b
False
>>> A > a
False
>>> b > A
True
>>> Z > a
False

هنگام بررسی دو رشته با یکدیگر، پایتون تک تک کاراکترهای معادل را بررسی می‌کند تا به اولین اختلاف برسد و سپس رشته‌ای را که کاراکتر باارزش‌تری داشته باشد به عنوان رشتۀ بزرگتر بر می‌گرداند.

عملگر متمم:not

ویرایش

زمانی که شما حاصل منطقی یک عبارت را محاسبه می‌کنید، قصد دارید از درست بودن آن مطلع شوید. امکان دارد بسته به شرایط برنامه هدف شما تشخیص نادرست بودن یا متمم آن یعنی not True باشد. عملگر یکتایی not فقط روی یک عملوند اجرا شده و نتیجۀ مخالف ارزش منطقی آن را برگشت می‌دهد.

>>> not True
False
>>> not 5
False
>>> not 0
True
>>> not 5 > 2
False

عملگرand

ویرایش

ممکن است در برنامه‌ای قصد برنامه‌نویس اطلاع از ترکیب چندین عبارت منطقی باشد تا بدین ترتیب برنامه بتواند مقایسه‌هایی بسیار پیچیده را انجام داده و در نتیجه تصمیمات درست‌تری اتخاذ کند. برای این منظور دو عملگر بسیار پرکاربرد موجود است. اولینِ آن‌ها، عملگرِ and (و منطقی) است. این عملگر تنها در حالتی به مقدار درست منجر می‌شود که هر دو عملوند آن حامل مقادیر درست باشند.

عملگر or

ویرایش

این عملگر تقریباً عکس and نتیجه می‌دهد یعنی در همۀ حالات به‌جز حالتی که هر دو عملوند آن مقدار نادرست داشته باشند منتج به مقدار درست خواهد شد.

عبارات شرطی (تصمیم‌گیری)

ویرایش

ifساده

ویرایش

پایتون با استفاده از روش بسیار ساده‌ای امکان تصمیم‌گیری در برنامه را فراهم می‌کند . برای این کار ابتدا از یک کلمۀ رزرو شده به‌نام if استفاده می‌شود. پس از این عبارت عبارت شرطی ظاهر می‌گردد که این عبارت هنگام اجرا تست شده و در صورت صحت نتیجۀ کلی آن قطعه‌کد مربوط به شرط به اجرا در می‌آید. خط شروع‌کنندۀ قطعۀ شرطی با کاراکتر دو نقطه (:) به پایان می‌رسد.

برای شروع برنامه‌ای می‌نویسیم که مقداری را از ورودی گرفته سپس علامت آن را اعلام می‌کند؛

Val = raw_input("enter a number: ")
Val = int(Val)

if Val > 0 :
    print "Entered value is positive!"
if Val < 0 :
    print "Entered value is negative!"

خروجی:

enter a number: -32
Entered value is negative!
enter a number: 24
Entered value is positive!
>>>

این برنامه چگونه عمل می‌کند؟ در این برنامه مفسر هر شرط را چک می‌کند. و در صورت درست بودن هر یک، قطعه‌کد مربوطه را اجرا می‌کند. در صورت درست بودن شرط اول دیگر نیاز به تست کردن شروط دیگر نداریم و سایر تست‌ها کاری بیهوده به حساب می‌آیند. برای جلوگیری از این مشکل در ادامه با ساختار جدیدی آشنا خواهیم شد.

ترکیب if و elif

ویرایش

اگر ما if را معادل اگر بگیریم elif هم‌معنی واژه‌ای مثل «و اگر نه» خواهد بود. این ترکیب با if شروع شده و با elif ها ادامه می‌یابد. در این حالت ابتدا شرط if اصلی تست می‌شود. در صورت درست بودن شرط، قطعه‌کد مربوطه اجرا شده و برنامه بدون تست شرط سایر elif ها به روند عادی اجرا ادامه می‌دهد. در صورتی که شرط نادرست باشد elif بعدی مورد پردازش قرار خواهد گرفت. تا زمانی که یکی از مقادیر شرطی elif معادل True باشد. ناگفته نماند که دستور elif بخشی از دستور if است و به‌طور جداگانه کاربردی ندارد.

if <شرط>:
    Code Block 1
elif <شرط دوم>:
    Code Block 2
elif <شرط سوم>:
    Code Block 3
....

تفاوت این گونه شرط‌ها این است که مفسر به محض درست شدن یکی از سلسله شرط‌ها از مابقی سلسله صرف‌نظر می‌کند. این خود یک عامل سرعت‌دهنده است. البته این روش تنها در مواردی خاص کاربرد دارد؛ که باید توسط نویسندۀ برنامه تشخیص داده شود و آن حالتی است که:

حداکثر یکی از این شرط‌ها در یک زمان برقرار باشد.

اکنون مثال سادۀ قبلی را توسط این روش بازنویسی می‌کنیم:

Val = raw_input("enter a number: ")
Val = int(Val)

if Val > 0 :
    print "Entered value is positive!"
elif Val < 0 :
    print "Entered value is negative!"

البته این کار در این برنامه تقریباً تأثیری ندارد اما در حالت‌های پیچیده‌تر آخر فصل با این امر بهتر مواجه خواهیم شد.

عبارتelse

ویرایش

این عبارت نیز نوعی شرط است اما به تنهایی کاربرد ندارد و باید بعد از if یا elif آورده شود. در واقع کاربرد تنهای آن یک خطا محسوب می‌شود. else این امکان را به ما می‌دهد که اگر در زنجیرۀ شرط‌های ما هیچ شرطی درست نبود قطعه‌کدی را که در خود دارد اجرا کند. همانطور در مثال‌ها و مطالب قبلی مشخص است، وجود این عبارت در شرط‌ها الزامی نیست و وجود آن باز هم به برنامه و کاری که برنامه‌نویس قصد انجامش دارد وابسته است. حال با این عبارت برنامۀ خود را گسترش داده و قابلیت تشخیص صفر را به آن اضافه می‌کنیم:

Val = raw_input("enter a number: ")
Val = int(Val)

if Val > 0 :
    print "Entered value is positive!"
elif Val < 0 :
    print "Entered value is negative!"
else :
    print "Entered value is zero"

خروجی:

enter a number: 0
Entered value is zero

مثال‌های عملی

ویرایش

مثال ۱: تبدیل شمارۀ روز به تاریخ

برنامه‌ای که شمارۀ یک روز از سال را بگیرد و اگر آن روز در سال گنجید. تاریخ معادل شمسی آن را چاپ کند.

day = input("Enter day number: ")

yLen = 365
mDay = 0
month = 0
#if the day is in first half of the year
if 0< day <= 186:
   month = day / 31 + (day % 31 > 0)
   mDay = day % 31

#if the day in the second half of the year
elif 186 < day <=365:
   day -= 186
   month = day / 30 + (day % 30 >0) + 6
   mDay = day % 30
 #day out of year
else:
   print "Bad day number entered"

print "in jalali calendar ---->" ,month, ".", mDay

در خطوط ۱۱ و ۱۷ چون از تقسیم صحیح استفاده شده است باقیمانده و اعشار در نظر گرفته نمی‌شود؛ پایتون به‌طور خودکار برای این عمل مثل جزء صحیح عمل کرده و حاصل را به طرف پایین گرد می‌کند. من با جمع بستن عبارت منطقی کاری شبیه به تابع جزء صحیح ریاضی انجام دادم و تقسیم را به طرف بالا گرد کردم. عبارات داخل پرانتز یک مقدار منطقی است که در صورت وجود باقیمانده در تقسیم مقدار ۱ و در غیر این صورت صفر خواهد بود.

خروجی برنامه:

 Enter day number: 366
 Bad day number entered
 in jalali calendar ----> 0 . 0

 >>>
 Enter day number: 56
 in jalali calendar ----> 2 . 25

 >>>
 Enter day number: 323
 in jalali calendar ----> 11 . 17
 >>>

حلقه ها

ویرایش

حلقۀ while

ویرایش

حلقۀ while ساده‌ترین و پرکاربردترین روش موجود در زبان پایتون برای تکرار قطعه‌کدی خاص است. این قطعه‌کد تا زمانی که شرط مورد نظر و از پیش تعیین شده‌ای درست باشد اجرا می‌شود. زمانی که شرط مورد بررسی نادرست شد اجرای برنامه از حلقه خارج شده و به اولین دستور بعد از حلقه یعنی اولین خطی که دقیقاً زیر عبارت while باشد، منتقل می‌شود. اگر هنگام اولین اجرا شرط مورد بررسی نادرست باشد کدهای داخل قطعه تکرار هیچ وقت اجرا نخواهد شد.

در زبان تفسیری پایتون دو نوع حلقه موجود است. نوع بعدی یعنی for در ادامه بررسی خواهد شد. کنترل برنامه پس از اجرای کامل قطعه‌کد داخل ساختار، دوباره به ابتدا برمی‌گردد و در صورت درست بودن شرط اجرا، دوباره کد داخل حلقه به اجرا در می‌آید. به همین دلیل به این قطعات کد «حلقه» گفته می‌شود. البته پایتون روش‌های بسیار ساده‌تری نیز دارد که می‌توان به جای حلقه‌ها از آن‌ها استفاده کرد. برای مثال دستوری چون map که با دریافت یک آرایه و یک تابع، تک تک اعضای آرایه را به تابع ارسال می‌کند. این ساختارها در درس‌های آتی به صورت کامل مورد بحث قرار خواهند گرفت.

ساختار کلی حلقۀ while

ویرایش

در پیچیده‌ترین حالت ممکن، این حلقه شامل یک آغازگر با عبارت while به همراه یک شرط اجرا می‌باشد که با دو نقطه به پایان می‌رسد. سپس در ادامه بدنه اصلی حلقه ظاهر می‌شود، که همگی دارای تورفتگی یکسان و برابر نسبت به خط آغازین هستند. بدنۀ اصلی تا زمانی که شرط مقابل عبارت while درست باشد اجرا خواهد شد. بخش بعدی این دستور یعنی بخش else آن اختیاری است. یعنی می‌توانید از این بخش بنا به نیاز برنامه استفاده نکنید. این بخش از کد در صورتی که حلقه به‌طور کامل اجرا شده و خاتمه یابد اجرا خواهد شد. در ادامه درس با دستور break آشنا خواهید شد که کار آن خاتمه دادن حلقه بدون بررسی شرط اجرای آن است. که در این صورت دستورات داخل بخش else اجرا نشده و برنامه از دستور بعدی حلقه به اجرای خود ادامه می‌دهد. شاید بهتر بود به‌جای عبارت else در این دستور از done یا on_completion استفاده می‌شد. اگر قبلاً با زبان‌های دیگری برنامه نوشته باشید حتماً با حالتی مواجه شده‌اید که باید پس از اتمام اجرای حلقه؛ در صورت کامل اجرا شدن آن کار خاصی را انجام دهید. در این حالت معمولاً شمارندۀ حلقه با مقدار پایانی مقایسه می‌شود. اما با فراهم آمدن دستور else برای حلقه این کار به‌صورت بسیار راحت‌تر و منطقی‌تری قابل اجرا است.

while <test>:     # شرط حلقه
    <statements1> # بدنۀ اصلی حلقه
else:             # بخش انتخابی
    <statements2> # اجرا زمانی که حلقه با روند عادی خاتمه یابد

مثال‌هایwhile

ویرایش

اولین و ساده‌ترین مثال ممکن یک حلقه است که برای همیشه، و تا زمانی که برنامه با روشی غیرمعمول خاتمه یابد؛ عبارتی را چاپ می‌کند. شرط این حلقه مقدار صحیح یک است که معادل True یا درست بوده و هیچگاه عوض نمی‌شود.

>>> while 1:
...     print 'Press Ctrl+C to stop me!'
...
Press Ctrl+C to stop me!
Press Ctrl+C to stop me!
Press Ctrl+C to stop me!
.....

مثال بعدی برنامه‌ای است که از مقدار متغییر a تا متغییر b را می‌شمارد. منطق استفاده شده بسیار شبیه زبان C است. معمولاً از چنین روش‌هایی در زبان پایتون استفاده نمی‌شود. بلکه با دستورات معادل و بسیار ساده‌تر و قابل‌فهم‌تر می‌توان به‌راحتی این برنامه را پیاده‌سازی کرد.

>>> a=0; b=10
>>> while a < b:
     print a,
     a = a+1

0 1 2 3 4 5 6 7 8 9

در این مثال با استفاده از کاراکتر ; دو دستور در سطر اول نوشته شده است. این کاراکتر در زبان C برای نمایش پایان دستور استفاده می‌شود. در پایتون نیز می‌توان از این کاراکتر و با همان هدف استفاده کرد. نکتۀ بعدی استفاده از یک ویرگول در انتهای دستور چاپ است. در حالت عادی دستور چاپ بعد از هر بار اجرا به سطر پایین می‌رود. ولی با استفاده از ویرگول عملیات چاپ از خط فعلی ادامه می‌یابد.

دستورات break ، continue ، pass و else برای حلقه

ویرایش

continue و break

ویرایش

پس از آشنایی با حلقه‌ها در پایتون اکنون با دو عبارت نسبتاً پرکاربرد آشنا می‌شویم که در داخل حلقه‌ها کاربرد فراوانی دارد. دو عبارت مهم ذکر شده عبارتند از continue و break. اگر شما آشنایی قبلی با این موارد در زبانی چون C داشته باشید اکثر مطالب این بخش برای شما آشنا خواهد بود. عبارت break مکمل یا نقطۀ مخالف دستور یا قطعۀ else در حلقه‌ها است. یعنی در صورت وجود بخش else یک حلقه، زمانی که از طریق دستور break روند عادی اجرای یک حلقه را قبل از اتمام عادی آن پایان می‌دهیم، قطعه‌کد درون else اجرا می‌شود. عبارت بعدی دستور pass است که در حقیقت با اجرای این دستور هیچ اتفاق خاصی رخ نخواهد داد. از این دستور زمانی استفاده می‌کنیم که در شرایطی خاص نیاز به انجام هیچ کاری نباشد! مثلاً برای تعریف یک تابع خالی تا بعداً کدهای آن نوشته شود. یا زمانی که بخواهیم هنگام بروز یک خطای خاص آن مشکل نادیده گرفته شده و برنامه به روند عادی خود ادامه دهد.

break

   خروج آنی و بدون تست شرط از داخلی‌ترین حلقۀ در حال اجرا

continue

   پرش به اول قطعه‌کد حلقه و تست شرط اجرای داخلی‌ترین حلقه. اگر شرط درست باشد کدهای درون قطعه دوباره اجرا می‌شود. در غیر این صورت حلقه خاتمه می‌یابد.

pass

   باعث بروز هیچ اتفاقی نمی‌شود. نام دیگر این عبارت عبارت تهی است.

قطعۀ else حلقه

   کدهای این قطعه تنها زمانی اجرا خواهد شد که حلقه با روند عادی خاتمه یابد (با دستور break ناتمام نماند)

ساختار عمومی و اصلی حلقۀwhile

ویرایش

زمانی که از دستورات break` و ``continue نیز در داخل حلقه استفاده شود؛ حالت کلی آن‌ها به صورت زیر خواهد بود:

while test:
    stements1
    if condition: break        # else خروج آنی از حلقه و عدم اجرای قطعۀ
    if condition: continue     # پرش به اول قطعۀ شرط و بررسی مجدد شرط اجرا
else:
    statements2                # اجرا نشده باشد و حلقه به‌صورت عادی خاتمه یابد  «break» اجرا در مواقعی که دستور

دستورات break و continue در هر بخش حلقه می‌توانند ظاهر شوند ولی معمولاً این دو دستور در داخل یک عبارت شرطی قرار می‌گیرند و در صورت صحت شرط، اجرا می‌شوند.

مثال: همان‌طور که گفته شد معمولاً از دستور pass برای تعریف توابع، کلاس‌ها یا سایر قطعه‌های خالی استفاده می‌شود. مثالی بسیار ساده از این دستور می‌تواند به‌صورت زیر باشد:

while 1: pass # type Ctrl-C to stop me!

این حلقه یک حلقۀ بی‌نهایت است که هیچ کاری را نیز انجام نمی‌دهد! در مثال بالا دستور و کد درون حلقه مستقیماً و در مقابل شروع‌کنندۀ حلقه یعنی عبارت while قرار دارند. همانند دستور شرطی if اگر دستور مورد نظر فقط یک سطر باشد این کار امکان‌پذیر است.

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

x = 10
while x:
    x = x-1
    if x % 2 != 0: continue
    print x,

خروجی مثال فوق:

8 6 4 2 0

شرط حلقه مقدار متغییر x است. پس این شرط فقط زمانی خاتمه می‌یابد که که مقدار x صفر باشد. همچنین در این مثال از عملگر % برای محاسبۀ باقیمانده استفاده شده است. اگر مقدار باقیماندۀ هر عدد تقسیم بر دو مخالف صفر باشد (عدد فرد باشد) روند اجرای برنامه به اول حلقه منتقل شده و پس از تست شرط دوباره اجرا می‌شود. اگر عدد زوج بوده و در نتیجه باقیمانده‌اش صفر باشد مقدار متغییر x چاپ می‌شود.

از دستور break معمولاً به‌عنوان کنترل‌کننده و خاتمه‌دهندۀ یک جستجو و یا خاتمۀ آنی حلقه به محض وقوع یک شرط خاص استفاده می‌شود.

مثال: کد زیر یک عدد را از لحاظ اول بودن تست می‌کند:

x = y / 2
while x > 1:
    if y % x == 0:               # بررسی اول بودن عدد
        print y, 'has factor', x
        break                    # else خروج آنی حلقه و عدم اجرای
    x = x-1
else:                            # اجرا به هنگام خروج عادی
    print y, 'is prime'

به‌جای قرار دادن یک نشانگر یا پرچم (flag) برای تست در شرط حلقه از دستور break برای خروج آنی در اولین رخداد استفاده شده است. یعنی زمانی که عدد مورد بررسی بخش‌پذیر بر یک عدد باشد. در این صورت بخش else نیز اجرا نخواهد شد. در این مثال برای بهینه‌سازی الگوریتم جستجو، بررسی مقسوم‌ها از نیمۀ مقسوم‌علیهشروع می‌شود. در صورتی که باقیماندۀ تقسیم عدد مورد نظر بر اعداد کوچکتر از نصف خود برابر صفر نباشد دستور break اجرا نشده و حلقه در حالت طبیعی و با حداکثر حالت‌های ممکنه اجرا می‌شود. همچنین داخل else نیز اجرا خواهند شد. به‌خاطر داشته باشید که بخش else ، حتی در صورت اجرا نشدن حلقه نیز اجرا خواهد شد. (یعنی زمانی که در اولین اجرا شرط نادرست بوده و اصلا دستورات داخل حلقه اجرا نشود.) مثلاً اگر متغییر y عدد یک یا کوچکتر باشد مستقیماً دستور داخل else اجرا می‌شود. و عبارت "is prime" نمایش داده خواهد شد.

حلقۀfor

ویرایش

حلقۀ for در پایتون در حقیقت یک پیمایشگر آرایه است. در این حالت عناصر موجود در لیست یا آرایۀ موجود تک تک پیمایش شده و هربار به عنوان مقدار متغییر حلقۀ مورد استفاده مقداردهی می‌شوند. حلقۀ for قادر است آرایه‌هایی از نوع رشته، لیست، تاپل و انواع جدید داده‌های ترتیبی و آرایه‌های که در درس‌های آینده معرفی می‌شوند را پیمایش کند.

ساختار کلی حلقۀfor

ویرایش

حلقۀ for در پایتون با یک شروع‌کننده آغاز می‌شود که کار اصلی آن تعریف یک یا چند متغیر به عنوان پیمایشگر و مشخص کردن آرایۀ مورد نظر برای پیمایش است..

for <متغیر پیمایشگر> in <object>:  # به متغیر پیمایشگر object مقدار دهی تک تک اعضای
    <statements>   # تکرار کد های داخل حلقه با متغیر پیمایشگر مقدار دهی شده
else:
    <statements>   # اجرا نگردد  break اجرا زمانی که دستور

زمانی که حلقۀ for در پایتون به اجرا در می‌آید تک تک عناصر توالی یا آرایۀ موجود با متغییر پیمایشگر نسبت داده شده و در حقیقت دستورات داخل حلقه برای تک تک عناصر اجرا می‌شود. این نوع خاص حلقه بسیار بهینه‌تر و ساده‌تر از حلقه‌های موجود در زبانی چون C است. که در آن برای پیمایش یک آرایه به یک متغییر به عنوان پیمایشگر یا ایندکس و نیز اطلاع از طول آرایه نیاز بود. حلقۀ for نیز درست مانند حلقۀ while دارای بخش else است. که نحوۀ اجرای آن دقیقاً مانند حلقۀ while است. دستورات continue و break نیز که در بالا توضیح داده شد به همان صورت مشابه مورد استفاده قرار می‌گیرد. با در نظر گرفتن این موارد ساختار عمومی و کلی حلقه for به‌شکل زیر است.

for <پیمایشگر> in <object>:
    <statements>
    if <test>: break
    if <test>: continue
else:
    <statements>

حلقه‌های شمارنده

ویرایش

حلقۀ for شاید اولین و مناسب‌ترین انتخاب برای ایجاد یک حلقۀ شمارشی یا توالی است. شاید ساختار حلقه در دید اول کمی تازه و مبهم به‌نظر برسد و شاید ایجاد یک حلقۀ ساده که برای مثال اعداد بین یک محدودۀ خاص را شمارش کند کاری سخت و دشوار به‌نظر رسد. اما پس از چند مثال و استفادۀ عملی از for خواهید دید که ساختار آن بسیار ساده، روان و قدرتمند است. به‌منظور شمارش محدوده‌ای از اعداد به‌وسیلۀ حلقۀ for از یک دستور با نام range استفاده می‌شود. این دستور با دریافت پارامترهای شروع، خاتمه و گام حرکت، یک لیست از اعداد صحیح موجود بین دو حد بالایی و پایینی با گام حرکت به مقدار تعیین‌شده را بر می‌گرداند.

>>> range(5), range(2, 5), range(0, 10, 2)
([0, 1, 2, 3, 4], [2, 3, 4], [0, 2, 4, 6, 8])

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

>>> for i in range(3):
       print i, 'Pythons'

0 Pythons
1 Pythons
2 Pythons

مثال‌های for

ویرایش

پیمایش یک لیست

حلقۀ while برخلاف for شباهت بسیاری به حلقۀ while موجود در C دارد. بنابراین برای درک بهتر حلقۀ for به مثال‌های بیشتری نیاز است. در اولین و ساده‌ترین مثال با استفاده از حلقۀ for عناصر یک لیست را چاپ می‌کنیم.

>>> for x in ["spam", "eggs", "ham"]:
     print x,

spam eggs ham

متغیر پیمایشگر x هر بار برابر با یکی از اعضای داخل لیست شده و دستورات داخل حلقه به ازای همان مقدار اجرا می‌شوند. ظاهر دستور بسیار شبیه به زبان انگلیسی است. برای مشخص شدن سهولت دستور فوق سعی کنید معادل آن را در زبان دیگری بنویسید. محاسبۀ حاصل جمع عناصر لیست

در مثال بعدی با استفاده از حلقۀ for حاصل جمع اعداد داخل یک لیست محاسبه می‌شود.

>>> sum = 0
>>> for x in [1, 2, 3, 4]:
     sum = sum + x

>>> sum
10

محاسبۀ حاصل‌ضرب عناصر لیست

با حلقه‌ای فشرده‌تر، حاصل‌ضرب اعداد درون لیست را محاسبه می‌کنیم:

>>> prod = 1
>>> for item in [1, 2, 3, 4]: prod = prod * item

>>> prod
24

پیمایش رشته

رشته نیز نوعی آرایه یا توالی از کاراکترها است و همانند یک آرایه یا لیست می‌توان با استفاده از حلقۀ for به تک تک عناصر آن دسترسی داشت.

>>> x = 'Python'
>>> for item in x:
       print item,

P  y  t  h  o  n

استفاده از چندین پیمایشگر

در مواردی که عناصر تشکیل دهندۀ لیست خود به‌صورت آرایه هستند، می‌توان از چندین متغیر به عنوان پیمایشگر استفاده کرد. در این حالت اگر از یک متغیر استفاده شود، متغیر هر بار برابر با یک آرایه درون لیست اصلی خواهد شد.

>>> T = [(1, 2), (3, 4), (5, 6)]
>>> for (a, b) in T:
     print a, b

1 2
3 4
5 6

مقایسۀ حلقه‌های for و while

ویرایش

دو روش بسیار پرکاربرد برای ایجاد حلقه‌ها یا قطعه‌کدهای تکرار شونده در پایتون وجود دارد. ماهیت این دو روش یکسان است و تقریباً همیشه می‌توان این دو حلقه را به‌جای یکدیگر استفاده کرد. اما استفادۀ نادرست از یک حلقه ممکن است باعث افزایش غیرالزامی حجم کد، افزایش تعداد متغییرها، گنگ بودن کد و بهینه نبودن و مشکلات دیگر شود.

معمولا در حالتی که تعداد تکرار مشخص نباشد از حلقۀ while و زمانی که تعداد تکرار مشخص باشد از حلقۀ for استفاده می‌شود. یک مثال برای مقایسه

در زیر دو مثال ذکر می‌شود که هر دو یک کار واحد را انجام می‌دهند. قصد داریم یک فایل را باز کرده و اطلاعات درون آن را به‌صورت خط‌به‌خط بخوانیم. برنامه‌نویسی سیستم فایل و کار با فایل‌ها در درس‌های آینده مطرح خواهد شد. با این وجود کد تک خطی استفاده شده برای این کار بسیار واضح است. خواندن فایل با استفاده از while

خواندن اطلاعات فایل به‌صورت خط‌به‌خط با استفاده از while :

file = open("test.txt", "r")
while 1:
    line = file.readline()     # خواندن یک خط از فایل
    if not line: break         # خروج از حلقه در صورت اتمام فایل
    Process line here

در این روش یک حلقۀ بی‌نهایت ایجاد شده و تا زمانی که فایل به انتهای خود نرسد عمل خواندن انجام می‌گیرد. در صورتی که فایل خاتمه یابد مقدار برگشتی تابع readline برابر با تهی یا None خواهد بود. و مقدار not line با فرض اینکه مقدار متغییر None باشد مقدار درست شده بنابراین دستور break اجرا می‌شود و حلقه خاتمه می‌یابد. خواندن فایل با استفاده از for

در حلقۀ for از تابع readlines استفاده شده که بر خلاف تابع readline کل فایل را به یکباره می‌خواند.

file = open("name", "r")
for line in file.readlines():
Process line here

حجم کد و خوانایی دو روش را مقایسه کنید! باز برای درک سهولت فوق‌العادۀ کدهای فوق سعی کنید تا همین کار را با یک زبان برنامه‌نویسی دیگر پیاده‌سازی کنید! متوجه فوق بسیار زیاد و سهولت و در عین حال قدرت بسیار زیاد زبان پایتون خواهید شد. مثال‌هایی سخت‌تر و عملی‌تر

پس از یادگیری حلقه‌ها و آشنایی با مفهوم کلی این مبحث، در این قسمت مثال‌هایی عملی و پیچیده‌تر مطرح می‌شود.

>>> omelet={"egg":2,"mushroom":5,"pepper":1,"cheese":1, "milk":1}
>>> ingredients = omelet.keys()
>>> ingredients
['cheese', 'pepper', 'egg', 'milk', 'mushroom']
>>> while len(ingredients) > 0:
...      current = ingredients.pop()
...      print "Adding %d %s to the mix" % (omelet[current],current)
...
Adding 5 mushroom to the mix
Adding 1 milk to the mix
Adding 2 egg to the mix
Adding 1 pepper to the mix
Adding 1 cheese to the mix

در این مثال ابتدا یک دیکشنری تعریف می‌شود. سپس از طریق دستور ()keys کلیدها (اندیس‌های) دیکشنری را در متغییر دیگری به نام ingredients ذخیره کرده و با وارد کردن نام آن محتویات متغییر را مشاهده می‌کنیم. (این نوع نمایش فقط در حالت محاوره‌ای امکان‌پذیر است). سپس با استفاده از حلقۀ while و تا زمانی که تعداد اعضای متغییر ingredients بزرگتر از صفر است وارد حلقه می‌شویم با دستور ()pop ـ که یک عنصر را از لیست جدا کرده (حذف کرده) و بر می‌گرداند ـ یکی یکی اعضای لیست ingredients که همان کلیدهای دیکشنری omelet هستند را در داخل متغییر current ریخته و در سطر بعدی چاپ می‌کنیم.

دستور بعدی برای حلقۀ ... for ... in است. که شبیه به دستور while می‌باشد با این تفاوت که در این حالت نیازی به تعیین شرط پایان حلقه نبوده و در ضمن متغییری که به تک تک عناصر لیست اشاره می‌کند ایجاد می‌شود، که می‌توانید از آن در داخل حلقه استفاده کنید.

معادل مثال بالا با for به صورت زیر است:

>>> for ingredient in omelet.keys():
...     print adding %d %s to the mix" % (omelet[ingredient],ingredient)

همان‌طور که مشاهده می‌کنید کد نوشته شده با for بسیار بهینه‌تر و کوتاه‌تر است.