سرفصل‌های آموزشی
آموزش پایتون
آشنایی با ساختار حلقه‌ی for در زبان برنامه‌نویسی پایتون

آشنایی با ساختار حلقه‌ی for در زبان برنامه‌نویسی پایتون

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

for target in object: # Assign object items to target
    #block(s) of statements, Repeated loop body: uses target

 ✨ برای آموزش ویدیویی پایتون اینجا کلیک کنید. ✨

در حالت عادی و بر اساس الگوی فوق هر حلقۀ for دقیقاً به تعداد عضوهای دنبالۀ object تکرار می‌شود بدین صورت که هر یک از اعضای دنباله به ترتیب و با شروع از عضو اول به متغیر target منتسب شده و دستورات داخل بدنۀ حلقه به ازای هر یک از انتساب‌ها اجرا می‌شوند و این پروسه تا زمان اِتمام اعضای دنبالۀ object ادامه پیدا می‌کند.

حال به منظور آشنایی بیشتر با ساختار دستور for و نحوۀ کارکرد آن در زبان برنامه‌نویسی پایتون مثالی را در ادامه بررسی می‌کنیم که در آن قصد داریم تا با کمک حلقۀ for هر یک از حروف استرینگ «SokanAcademy» را به صورت جداگانه در خروجی چاپ کنیم:

letterNum = 0
for letter in "SokanAcademy":
    letterNum += 1
    print("Letter ", letterNum, " is ", letter,".")
print("SokanAcademy has", letterNum, "letters.")

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

در سطر بعد یک دستور مرکب تعریف کرده‌ایم که با کیورد for آغاز شده سپس شناسۀ یک متغیر دلخواه همچون letter و به دنبال آن کیورد in را آورده‌ایم و بدین ترتیب به مفسر پایتون گفته‌ایم که در ادامه داده‌ای از نوع دنباله و از جنس استرینگ با مقدار «SokanAcademy» را مد نظر قرار دهد (توجه داشته باشیم که دنباله‌ها انواع مختلفی دارند که در آموزش‌های آینده با آن‌ها آشنا خواهیم شد.)

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

همان‌طور که در آموزش‌های گذشته اشاره کردیم، آبجکت‌های استرینگ از نوع دادۀ دنباله هستند چرا که هر آبجکت استرینگ از تعدادی حروف تشکیل شده است که به ترتیب و پشت‌ سر هم در یک ردیف آمده‌اند و جایگاه هر یک از حروف در این دنباله ثابت است به طوری که عوض کردن جایگاه هر یک از اعضای دنباله منجر به ایجاد دنبالۀ جدیدی می‌شود. برای مثال، دنباله‌هایی همچون «eat» و «ate» از حروف یکسانی تشکیل شده‌اند اما ترتیب اعضای آن‌ها متفاوت بوده و از همین روی دو دنبالۀ متفاوت محسوب می‌شوند.

حال به مثال فوق برمی‌گردیم و در ادامۀ تعریف دنباله‌ای از جنس استرینگ، سربند دستور مرکب for را با علامت : به پایان می‌رسانیم و بدین ترتیب به مفسر پایتون می‌گوییم به ازای هر یک از حروف دنبالۀ «SokanAcademy» دستورات بدنۀ داخلی را اجرا کند که برای دسترسی به هر یک از حروف دنباله نیز از متغیر letter استفاده می‌کنیم بدین صورت که در هر بار تکرار حلقۀ for حروف دنبالۀ «SokanAcademy» به ترتیب به متغیر letter منتسب می‌شوند.

در ادامه دستورات بدنۀ داخلی حلقۀ for را با رعایت تورفتگی نسبت به بلوک سربند و در یک بلوک مجزا می‌نویسیم به طوری که در هر نوبت از اجرای حلقهٔ for توسط مفسر اجرا می‌شوند و در هر بار یک واحد به متغیر letterNum افزوده شده و دستور ()print اجرا می‌شود.

در واقع، فانکشن ()print را داخل حلقۀ for با پنج آرگومان ورودی فراخوانی کرده‌ایم که در آن گفته‌ایم در هر بار اجرای حلقه آخرین مقدار منتسب به متغیر letterNum یا به عبارتی اندیس هر حرف از دنبالۀ فوق‌الذکر و همچنین مقدار متناظر آن از متغیر letter یا هر یک از حروف مربوطه از دنباله را به همراه استرینگ‌های تعریف‌شده در خروجی چاپ کند و در نهایت پس از خروج از بدنۀ حلقۀ for فانکشن ()print را با آرگومان ورودی letterNum فراخوانی کرده‌ایم تا پس از پایان تکرارها در حلقۀ for تعداد حروف دنبالۀ مذکور را در خروجی چاپ کند.

اسکریپت این برنامه را در فایلی به نام forLoop.py ذخیره کرده و آن را اجرا می‌کنیم که در خروجی خواهیم داشت:

Letter  1  is  S .
Letter  2  is  o .
Letter  3  is  k .
Letter  4  is  a .
Letter  5  is  n .
Letter  6  is  A .
Letter  7  is  c .
Letter  8  is  a .
Letter  9  is  d .
Letter  10  is  e .
Letter  11  is  m .
Letter  12  is  y .
SokanAcademy has 12 letters.

همان‌طور که اشاره کردیم، در حالت عادی حلقۀ for به ازای تمامی اعضای دنباله اجرا می‌شود اما نکتۀ قابل‌توجه اینکه در حلقۀ for نیز همچون حلقۀ while با به‌کارگیری کیوردهای break و continue یا دستور else می‌توانیم جریان عادی اجرای حلقه را کنترل کنیم که در ادامه کاربرد هر یک از دستورها را در حلقۀ for و در قالب چند مثال بررسی می‌کنیم.

کاربرد دستور break در حلقۀ for

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

username = input("Enter a username less than 6 characters: ")
letterNum = 1
for letter in username:
    print("Letter ", letterNum, " is ", letter)
    letterNum += 1
    if letterNum > 6:
        print("Your username is too long!")
        break

در کد فوق متغیری تحت عنوان username تعریف کرده و کلمۀ ورودی توسط کاربر را به آن منتسب می‌کنیم و در ادامه متغیری به نام letterNum تعریف می‌کنیم که این متغیر را به منظور شمارش تعداد حروف کلمۀ ورودی به کار می‌گیریم. در ادامه دستور for را تعریف کرده‌ایم که در آن گفته‌ایم هر یک از حروف کلمۀ ذخیره‌شده در متغیر username به ترتیب به متغیر letter منتسب شده و توسط فانکشن ()print در خروجی چاپ شوند و به ازای هر بار اجرای حلقۀ for نیز یک واحد به متغیر letterNum اضافه شده و به همراه هر یک از حروف کلمۀ ورودی در خروجی چاپ شوند.

حال اگر مقدار منتسب به متغیر letterNum بیشتر از شش شود یا به عبارتی کلمۀ ورودی کاربر بیش از شش کاراکتر داشته باشد به طوری که حلقۀ for برای بار ششم اجرا شده و مقدار متغیر letterNum برابر با عدد هفت گردد، شرط سطر ششم True ارزیابی شده و دستورات بدنۀ داخلی آن اجرا می‌شوند که در آن گفته‌ایم استرینگ «!Your username is too long» در خروجی چاپ شده و در ادامه دستور break اجرا شود که در نهایت برنامه به طور کامل از حلقۀ for خارج شده و ادامۀ حروف کلمۀ ورودی را چاپ نمی‌کند.

اسکریپت این برنامه را در فایلی به نام forBreak.py ذخیره کرده و آن را اجرا می‌کنیم که در خروجی خواهیم داشت:

Enter a username less than 6 characters: NargesAsadi
Letter  1  is  N
Letter  2  is  a
Letter  3  is  r
Letter  4  is  g
Letter  5  is  e
Letter  6  is  s
Your username is too long!

همان‌طور که می‌بینید، حلقۀ for شش مرتبه اجرا شده سپس برنامه به طور کامل از آن خارج شده و سایر کاراکترهای کلمۀ ورودی را چاپ نکرده است.

کاربرد دستور continue در حلقۀ for

در این مرحله مثالی مد نظر قرار می‌دهیم که در آن قصد داریم تا تعداد حروف استرینگ «SokanAcademy» را در خروجی چاپ کنیم به طوری که حروف a یا A از آن نادیده گرفته شده و چاپ نشوند که برای این منظور کدی مانند زیر خواهیم داشت:

letterNum = 0
for letter in "SokanAcademy":
    letterNum += 1
    if (letter == "a" or letter == "A"):
        print("Letter ", letterNum, " is ", letter, "and not processed.")
        continue   
    print("Letter ", letterNum, " is ", letter)

در کد فوق یک دستور if در بدنۀ داخلی حلقۀ for تعریف کرده و در آن گفته‌ایم چنانچه مقدار منتسب به متغیر letter برابر با هر یک از حروف a یا A باشد، شرط برقرار بوده و دستورات بدنۀ داخلی آن اجرا شوند و بدین ترتیب فانکشن ()print فراخوانی شده و منجر به چاپ هر یک از حروف a یا A و همچنین اندیس متناظرشان به همراه استرینگ فوق‌الذکر در خروجی می‌شود و در ادامه دستور continue اجرا شده و بدین ترتیب سایر دستورهای برنامه نادیده گرفته می‌شوند به طوری که مفسر مجدداً به ابتدای حلقه بازمی‌گردد و دور بعدی تکرار حلقه را با حرف بعدی شروع می‌کند.

اسکریپت این برنامه را در فایلی به نام forContinue.py ذخیره کرده و آن را اجرا می‌کنیم که در خروجی خواهیم داشت:

Letter  1  is  S
Letter  2  is  o
Letter  3  is  k
Letter  4  is  a and not processed.
Letter  5  is  n
Letter  6  is  A and not processed.
Letter  7  is  c
Letter  8  is  a and not processed.
Letter  9  is  d
Letter  10  is  e
Letter  11  is  m
Letter  12  is  y

همان‌طور که می‌بینید، حروف چهارم، ششم و هشتم در خروجی چاپ نشده‌اند. حال فرض کنید به جای دستور continue در کد فوق از دستور break استفاده کنیم که در چنین شرایطی با اجرای حلقۀ for و رسیدن به هر یک از حروف A یا a دستور break اجرا شده و برنامه از حلقۀ تکرار خارج می‌شود و بدین ترتیب سایر اعضای دنباله نادیده گرفته شده و چاپ نمی‌شوند اما این در حالی است که دستور continue تنها یک دور از تکرار حلقۀ for را نادیده گرفته و اجرای آن را از ابتدا آغاز می‌کند.

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

کاربرد فانکشن ()range در حلقۀ for

فرض کنید بخواهیم دنباله‌ای از اعداد صحیح 0 تا 9 را در یک حلقۀ for مورد استفاده قرار دهیم که یکی از روش‌های ایجاد این دنباله استفاده از فانکشن از پیش تعریف‌شدۀ ()range است که برای آشنایی با کاربردهای فانکشن ()range در حلقۀ for برنامۀ زیر را مد نظر قرار می‌دهیم:

# range(stop)
for i in range(10):
    print(i)

در کد فوق فانکشن ()range را با یک آرگومان ورودی فراخوانی کرده‌ایم که به عنوان نقطۀ پایانی دنباله در نظر گرفته شده و دنباله‌ای از اعداد صحیح کمتر از آن (بازۀ 0 تا 9) را ریترن می‌کند. همان‌طور که می‌بینید، در حلقۀ for گفته‌ایم به ازای هر یک از مقادیر دنبالۀ مذکور فانکشن ()print فراخوانی شده و اعداد بازۀ 0 تا 9 را در خروجی چاپ کند.

اسکریپت این برنامه را در فایلی به نام range.py ذخیره کرده و آن را اجرا می‌کنیم که در خروجی خواهیم داشت:

0
1
2
3
4
5
6
7
8
9

حال اگر بخواهیم دنباله‌ای از اعداد صحیح را در بازه‌ای مشخص در خروجی چاپ کنیم، از الگوی (range(start, stop استفاده می‌کنیم و بدین ترتیب دو آرگومان ورودی به فانکشن ()range می‌دهیم که به عنوان نقطۀ شروع و پایان بازۀ مذکور در نظر گرفته می‌شوند. برای مثال، برنامۀ زیر را مد نظر قرار می‌دهیم:

# range(start, stop)
for i in range(5, 10):
    print(i)

در برنامۀ فوق گفته‌ایم اعداد صحیح متعلق به بازۀ 5 تا 10 در هر بار اجرای حلقۀ for به ترتیب به متغیر i منتسب شده در خروجی چاپ شوند که خروجی حاصل از اجرای برنامه بدین ترتیب خواهد بود:

5
6
7
8
9

همان‌طور که می‌بینید، آرگومان ورودی اول به فانکشن ()range به عنوان اولین عدد از دنبالۀ فوق در نظر گرفته شده و اعداد بعدی نیز به ترتیب چاپ شده‌اند و با رسیدن به نقطۀ انتهایی (عدد صحیح 10) دنباله پایان یافته و خود عدد مربوط به آرگومان دوم (نقطۀ پایانی) به عنوان عضو دنباله محسوب نشده است.

نکته در الگوی فانکشن (range(start, stop هر یک از آرگومان‌های ورودی اول و دوم می‌توانند اعداد صحیحی با مقادیر منفی باشند اما در چنین شرایطی عدد مربوط به آرگومان ورودی اول می‌باید از عدد آرگومان دوم کوچک‌تر باشد و در غیر این صورت دنباله‌ای بدون عضو تولید می‌شود.

همچنین اگر بخواهیم دنباله‌ای از اعداد صحیح با فاصله‌ای یکسان از یکدیگر تولید کنیم به طوری که اعداد دنباله بیش از یک واحد با هم اختلاف داشته باشند از فانکشن ()range بر اساس الگوی (range(start, stop, step استفاده می‌کنیم. برای مثال، برنامۀ زیر را در نظر می‌گیریم:

# range(start, stop, step)
for i in range(0, 20, 3):
    print(i)

در کد فوق فانکشن ()range را با سه آرگومان ورودی فراخوانی کرده‌ایم که در آن گفته‌ایم دنباله‌ای از اعداد صحیح با شروع از عدد 0 تا 20 (غیر از خود عدد 20) در خروجی چاپ شود به طوری که هر عضو با عضو قبل و بعد خود سه واحد اختلاف داشته باشد که با اجرای این کد در خروجی خواهیم داشت:

0
3
6
9
12
15
18

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

# range(start, stop, negativeStep)
for i in range(20, 2, -2):
    print(i)

در کد فوق گفته‌ایم دنبالۀ اعداد صحیح به صورت نزولی و با شروع از عدد 20 چاپ شود به طوری که اعداد دنباله به اندازۀ دو واحد با هم اختلاف داشته و آرگومان پایان‌دهندۀ فانکشن ()range یا به عبارتی عدد 0 در این مثال در خروجی چاپ نشود که با اجرای این کد در خروجی خواهیم داشت:

20
18
16
14
12
10
8
6
4
2 

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

به‌کارگیری حلقه‌های for تودرتو

پیش از این گفتیم که دستورهای مرکب در زبان برنامه‌نویسی پایتون را می‌توان به صورت تودرتو و در بدنۀ داخلی یکدیگر استفاده کرد و از همین روی، همچون تعریف دستور if در بدنۀ یک حلقۀ تکرار، می‌توانیم یک حلقۀ for را در بدنۀ داخلی حلقۀ for دیگر تعریف کنیم که برای درک بهتر این موضوع مثال زیر را بررسی می‌کنیم:

for i in range(1, 4):
    for j in range(1, 4):
        print(i, "*", j, " = ", i * j) 

در برنامۀ فوق دو حلقۀ for تودرتو تعریف کرده‌ایم که در آن گفته‌ایم به ازای هر یک از اعداد صحیح منتسب به متغیر i در بازه اعداد 1 تا 4 (غیر از عدد 4) حلقۀ داخلی تکرار شده و در هر مرحله هر یک از اعداد بازۀ مذکور را به متغیر j منتسب کرده و در ادامه به مقدار منتسب به متغیر i ضرب کند و حاصل را در خروجی چاپ کند. به عبارتی، حلقۀ داخلی به ازای هر یک از مقادیر منتسب به متغیر i سه مرتبه تکرار شده و حاصل‌ضرب آن در مقدار متغیر j را در خروجی چاپ می‌کند.

اسکریپت برنامه را در فایلی به نام nestedLoop.py ذخیره کرده و آن را اجرا می‌کنیم که در خروجی خواهیم داشت:

1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
3 * 1 = 3
3 * 2 = 6
3 * 3 = 9

همان‌طور که می‌بیند، به ازای هر یک از اعداد منتسب به متغیر i حلقۀ داخلی سه مرتبه تکرار شده و اعداد بازۀ 1 تا 4 یک‌به‌یک به متغیر j منتسب شده و در ادامه مقادیر هر یک از متغیرهای i و j در هم ضرب شده‌اند و در گام بعد عدد دوم از دنبالۀ اعداد صحیح به متغیر i منتسب شده و به ازای آن نیز حلقۀ داخلی سه مرتبه تکرار شده و هر یک از مقادیر بازۀ 1 تا 4 به متغیر j منتسب شده است و در نهایت مقادیر متغیرهای i و j در هم ضرب شده‌اند که این پروسه تا زمان اِتمام انتساب هر یک از مقادیر بازۀ اعداد صحیح به متغیر i ادامه می‌یابد.

به‌کارگیری دستور else در حلقۀ for

در آموزش‌های گذشته به بررسی این موضوع پرداختیم که با به‌کارگیری دستور else در حلقۀ while بدنۀ داخلی این دستور در صورتی اجرا می‌شود که برنامه با اجرای دستور break از بدنۀ حلقۀ while خارج نشود و در حلقۀ for نیز می‌توانیم از دستور else استفاده کنیم که فرم کلی آن بدین صورت می‌باشد:

for target in object: # Assign object items to target
    #statements  Repeated loop body: use target
else: # Optional else part
    #statements  If we didn't hit a 'break'

در ادامه به منظور آشنایی با نحوۀ به‌کارگیری دستور else در حلقۀ for مثالی را مد نظر قرار می‌دهیم که در آن قصد داریم تا ببینیم عدد ورودی توسط کاربر عددی اول است یا خیر که برای این منظور ابتدا لازم است تا نکته‌ای را بیان کنیم.

نکته عدد اول عددی است که به غیر از خودش و 1 مقسوم‌علیه دیگری ندارد بدین معنی که باقی‌ماندۀ تقسیم یک عدد اول بر تمام اعداد کوچک‌تر از خودش به جز عدد 1 برابر با 0 نمی‌باشد.

حال به مثال فوق برمی‌گردیم و برای پیاده‌سازی آن کدی مانند زیر را مد نظر قرار می‌دهیم:

n = int(input("Enter a number -->"))
for i in range(2, n):
    if n % i == 0:
        print(n, "is not a prime number")
        break
else:
    print(n, "is a prime number")

در کد فوق متغیری به نام n تعریف کرده و عدد ورودی از سمت کاربر را در آن نگهداری می‌کنیم. در سطر بعد با به‌کارگیری حلقۀ for و فراخوانی فانکشن ()range در آن بازه‌ای از اعداد صحیح دو عدد ورودی تولید کرده و گفته‌ایم عدد ورودی به تک‌تک اعداد این بازه تقسیم شود و چنانچه باقی‌ماندۀ تقسیم برابر با صفر شود شرط برقرار بوده و استرینگ مربوط به اول نبودن عدد مذکور در خروجی چاپ شود و در ادامه دستور break اجرا شده و برنامه به طور کامل از حلقه خارج می‌گردد که در چنین شرایطی بدنۀ داخلی دستور else پس از حلقۀ for اجرا نمی‌شود.

اسکریپت این برنامه را در فایلی به نام forElse.py ذخیره کرده و آن را اجرا می‌کنیم که به عنوان یک مثال در خروجی داریم:

Enter a number -->25
25 is not a prime number.

با اجرای برنامه عدد 25 به متغیر n منتسب شده و در ادامه حلقۀ for اجرا می‌شود که بازه‌ای از اعداد صحیح از 2 تا 25 (به جز عدد 25) تولید شده و عدد ورودی بر تمامی اعداد کوچک‌تر از خودش تقسیم می‌شود و در هر بار تقسیم اعداد شرط if چک می‌شود و در صورتی که باقی‌مانده برابر با 0 باشد استرینگ مربوط به اول نبودن عدد چاپ می‌شود که باقی‌ماندۀ تقسیم عدد 25 بر عددی همچون 5 برابر با 0 شده و در ادامه با اجرای دستور break برنامه از حلقه خارج شده و دستور else نیز اجرا نمی‌گردد. یک بار دیگر برنامۀ forElse.py را اجرا کرده و عدد 23 را به عنوان ورودی به آن می‌دهیم که در خروجی خواهیم داشت:

Enter a number -->23
23 is a prime number

در واقع، عدد 23 بر هیچ یک از اعداد کوچک‌تر از خودش بخش‌پذیر نبوده و در هیچ یک از تکرارهای حلقۀ for شرط if برقرار نمی‌گردد و بدنۀ آن اجرا نمی‌شود و از همین روی برنامه با اجرای دستور break از حلقه خارج نمی‌شود که بدین ترتیب دستور بدنۀ داخلی else اجرا شده و فانکشن ()print استرینگ مربوط به اول بودن عدد را در خروجی چاپ می‌کند.