رفتن به محتوا
پایتون از صفراصول زباندرس ۳ از ۱۰

شرط و حلقه

برنامه‌ای که تصمیم می‌گیرد و تکرار می‌کند: if و elif و else، تورفتگی (indent) و دونقطه، حلقه‌ی for با range و روی متن، حلقه‌ی while، break و continue، حلقه‌ی بی‌پایان و Ctrl+C؛ با بازی حدس عدد و FizzBuzz.

  • حدود ۱۷ دقیقه مطالعه
  • ۸ مثال اجراشده
  • ۳ تمرین با جواب
  • مقدماتی تا متوسط
  • به‌روزرسانی: ۲۹ مهر ۱۴۰۵

توی این درس یاد می‌گیری برنامه را تصمیم‌گیر و تکرارکننده کنی. با if، elif و else بسته به شرایط کار متفاوتی می‌کنی، و می‌فهمی چرا در پایتون دونقطه (:) و تورفتگی (فاصله‌ی ابتدای خط) این‌قدر مهم‌اند. با حلقه‌ی for کاری را چند بار یا روی هر حرف یک متن انجام می‌دهی، با while تا وقتی شرطی برقرار است ادامه می‌دهی، و با break و continue حلقه را کنترل می‌کنی. در آخر یک بازی «حدس عدد» می‌سازی.

مسئله: برنامه‌ای که همیشه یک کار می‌کند

Section titled “مسئله: برنامه‌ای که همیشه یک کار می‌کند”

برنامه‌های دو درس قبل از بالا به پایین اجرا می‌شدند و همیشه یک کار می‌کردند. ولی برنامه‌ی واقعی باید تصمیم بگیرد («اگر رمز درست بود وارد شو، وگرنه خطا بده») و تکرار کند («برای هر فایل در این پوشه…»، «تا وقتی کاربر q نزده…»). این دو ابزار، یعنی شرط و حلقه، تقریباً در هر برنامه‌ای هستند.

تشبیه: چراغ راهنمایی و دور زدن پیست

Section titled “تشبیه: چراغ راهنمایی و دور زدن پیست”

شرط مثل چراغ راهنمایی است: اگر سبز بود برو، اگر زرد بود آهسته کن، وگرنه بایست. فقط یکی از این کارها انجام می‌شود. حلقه مثل دور زدن پیست است: for یعنی «دقیقاً ده دور بزن» (تعداد از قبل معلوم است) و while یعنی «تا وقتی بنزین داری دور بزن» (تعداد از قبل معلوم نیست).

if شرط را می‌سنجد؛ اگر درست بود بلوک تورفته اجرا می‌شود، وگرنه سراغ elif بعدی یا else می‌رود. فقط یکی از شاخه‌ها اجرا می‌شود.
license.py
age = int(input("سن: "))
if age >= 18:
print("می‌توانی گواهینامه بگیری.")
print("مبارک باشد!")
print("پایان برنامه")
صفحه (جواب: 20)
سن: 20
می‌توانی گواهینامه بگیری.
مبارک باشد!
پایان برنامه
صفحه (جواب: 15)
سن: 15
پایان برنامه

سه چیز را با دقت ببین:

  1. بعد از شرط یک دونقطه (:) آمده.
  2. خط‌هایی که «مال» if هستند چهار فاصله جلوتر شروع شده‌اند. به این تورفتگی (indentation) می‌گویند و به این خط‌ها یک بلوک.
  3. print("پایان برنامه") دوباره از ستون اول شروع شده، پس دیگر جزو if نیست و همیشه اجرا می‌شود.

در خیلی از زبان‌ها بلوک را با { } مشخص می‌کنند؛ در پایتون فقط با تورفتگی. برای همین فاصله‌ی ابتدای خط در پایتون معنی دارد. nano با زدن Tab چهار فاصله نمی‌گذارد؛ خودت چهار بار Space بزن (یا در درس‌های بعد یک ویرایشگر کد مثل VS Code بگیر که خودش این کار را می‌کند).

مثال ۲: چند شاخه، elif و else

Section titled “مثال ۲: چند شاخه، elif و else”
grade.py
score = int(input("نمره (۰ تا ۲۰): "))
if score >= 17:
print("عالی")
elif score >= 12:
print("قبول")
elif score >= 10:
print("قبول، ولی با زحمت")
else:
print("مردود")
خروجی (چهار اجرا با 18، 13، 10 و 4)
نمره (۰ تا ۲۰): 18
عالی
نمره (۰ تا ۲۰): 13
قبول
نمره (۰ تا ۲۰): 10
قبول، ولی با زحمت
نمره (۰ تا ۲۰): 4
مردود

پایتون شرط‌ها را به ترتیب می‌سنجد و اولین شرط درست را اجرا می‌کند، بعد بقیه را رد می‌کند. برای همین با ۱۸ فقط «عالی» چاپ شد، با اینکه ۱۸ از ۱۲ و ۱۰ هم بزرگ‌تر است. else (اختیاری) یعنی «اگر هیچ‌کدام درست نبود». ترتیب مهم است: اگر score >= 10 را اول می‌نوشتی، ۱۸ هم «قبول، ولی با زحمت» می‌شد.

⚡ بررسی سریع

در یک if/elif/else با نمره‌ی ۱۸، چند شاخه اجرا می‌شود؟

for یک بلوک را برای هر عضو از یک دنباله اجرا می‌کند. range(n) دنباله‌ی عددهای 0 تا n-1 است:

loop.py
for i in range(5):
print("دور", i)
print("---")
for i in range(1, 11, 3):
print(i)
print("---")
for ch in "سلام":
print(ch)
خروجی
دور 0
دور 1
دور 2
دور 3
دور 4
---
1
4
7
10
---
س
ل
ا
م
شکل عددها
range(5) 0، 1، 2، 3، 4 (پنج عدد، از صفر، بدون خود ۵)
range(1, 6) 1 تا 5 (شروع تا قبل از پایان)
range(1, 11, 3) 1، 4، 7، 10 (قدم ۳)
range(10, 0, -1) 10 تا 1 (رو به عقب)

for روی هر دنباله‌ای کار می‌کند: روی متن، هر بار یک حرف؛ و در درس بعد روی لیست، هر بار یک عضو. اسم متغیر (i، ch) را خودت انتخاب می‌کنی.

مثال ۴: جمع کردن در حلقه

Section titled “مثال ۴: جمع کردن در حلقه”

الگوی بسیار رایج: یک متغیر را قبل از حلقه صفر کن و داخل حلقه به آن اضافه کن:

sum.py
total = 0
for n in range(1, 101):
total += n
print("جمع ۱ تا ۱۰۰:", total)
evens = 0
for n in range(1, 21):
if n % 2 == 0:
evens += 1
print("تعداد زوج‌ها در ۱ تا ۲۰:", evens)
خروجی
جمع ۱ تا ۱۰۰: 5050
تعداد زوج‌ها در ۱ تا ۲۰: 10

دومی یک if داخل یک for است، پس تورفتگی‌اش دو برابر (هشت فاصله) است. هر سطح تو در تو، چهار فاصله‌ی بیشتر.

while تا وقتی شرطش درست است تکرار می‌کند:

countdown.py
count = 3
while count > 0:
print(f"{count}...")
count -= 1
print("پرتاب!")
خروجی
3...
2...
1...
پرتاب!

در هر دور، count یکی کم می‌شود؛ وقتی به صفر رسید، شرط count > 0 غلط می‌شود و حلقه تمام می‌شود. همیشه مطمئن شو چیزی داخل حلقه شرط را بالاخره غلط می‌کند (مثال ۸).

for وقتی است که می‌دانی روی چه چیزی یا چند بار تکرار کنی؛ while وقتی که فقط شرط توقف را می‌دانی.
control.py
for n in range(1, 10):
if n == 3:
continue
if n == 6:
break
print(n)
خروجی
1
2
4
5
  • continue: بقیه‌ی همین دور را رها کن و برو دور بعد (۳ چاپ نشد).
  • break: کل حلقه را همین‌جا تمام کن (به ۶ که رسید، حلقه تمام شد و ۶ تا ۹ چاپ نشدند).

همه‌ی این‌ها با هم. import random یک ماژول آماده را می‌آورد (درس «خطا و ماژول») و random.randint(1, 10) یک عدد تصادفی بین ۱ و ۱۰ می‌دهد:

guess.py
import random
secret = random.randint(1, 10)
tries = 0
while True:
guess = int(input("حدس بزن (۱ تا ۱۰): "))
tries += 1
if guess < secret:
print("بزرگ‌تر")
elif guess > secret:
print("کوچک‌تر")
else:
print(f"درست بود! با {tries} حدس.")
break
صفحه (عدد مخفی این بار ۷ بود)
حدس بزن (۱ تا ۱۰): 5
بزرگ‌تر
حدس بزن (۱ تا ۱۰): 9
کوچک‌تر
حدس بزن (۱ تا ۱۰): 7
درست بود! با 3 حدس.

while True یعنی «برای همیشه»؛ تنها راه خروج break است که فقط با حدس درست اجرا می‌شود. این الگو («تا وقتی کاربر کار درست را نکرده، دوباره بپرس») خیلی رایج است.

مثال ۸: حلقه‌ی بی‌پایان و Ctrl+C

Section titled “مثال ۸: حلقه‌ی بی‌پایان و Ctrl+C”

این برنامه یادش رفته n را زیاد کند:

forever.py
n = 1
while n < 5:
print(n)

n همیشه ۱ است، پس شرط همیشه درست است و برنامه تا ابد 1 چاپ می‌کند. با Ctrl+C متوقفش کن:

صفحه (بعد از Ctrl+C)
1
1
1
^CTraceback (most recent call last):
File "/home/ali/py/forever.py", line 3, in <module>
print(n)
KeyboardInterrupt

KeyboardInterrupt خطا نیست؛ یعنی «کاربر با کیبورد قطعش کرد». راه‌حل: داخل حلقه n += 1 بگذار.

پشت پرده: شرط فقط True یا False می‌خواهد

Section titled “پشت پرده: شرط فقط True یا False می‌خواهد”

if و while در واقع فقط یک سؤال می‌پرسند: «این عبارت True است یا False؟». مقایسه‌ها (age >= 18) مستقیم True/False می‌دهند، ولی هر مقدار دیگری هم کار می‌کند: پایتون آن را مثل bool() (درس قبل) تبدیل می‌کند. پس if name: یعنی «اگر متن خالی نیست» و if count: یعنی «اگر صفر نیست». و for در پشت صحنه از دنباله می‌خواهد «عضو بعدی را بده» تا وقتی دنباله بگوید «تمام شد»؛ برای همین روی متن، لیست، range و (در درس فایل‌ها) روی خط‌های یک فایل یکسان کار می‌کند.

ساختار شکل
شرط ساده if شرط: + بلوک تورفته
چند شاخه if ...: / elif ...: / else:
حلقه روی دنباله for x in دنباله:
حلقه‌ی عددی for i in range(شروع, پایان, قدم):
حلقه‌ی شرطی while شرط:
خروج از حلقه break
رفتن به دور بعد continue
خطا معنی
SyntaxError: expected ':' دونقطه‌ی آخر if/for/while جا افتاده
IndentationError: expected an indented block بعد از : خط تورفته نیامده
IndentationError: unexpected indent تورفتگی بی‌دلیل
KeyboardInterrupt کاربر Ctrl+C زد
bad.py
age = 20
if age > 18
print("بزرگسال")
خروجی
File "/home/ali/py/bad.py", line 2
if age > 18
^
SyntaxError: expected ':'
bad2.py
age = 20
if age > 18:
print("بزرگسال")
خروجی
File "/home/ali/py/bad2.py", line 3
print("بزرگسال")
^
IndentationError: expected an indented block after 'if' statement on line 2

پایتون صریحاً می‌گوید بعد از if خط ۲ منتظر یک بلوک تورفته بوده. راه‌حل: چهار فاصله.

اگر بعضی خط‌ها را با Tab و بعضی را با Space تو ببری، ممکن است در ویرایشگر یکی به نظر برسند ولی پایتون TabError بدهد. راه‌حل: همیشه چهار Space.

شرط کلی‌تر (score >= 10) قبل از شرط خاص‌تر (score >= 17) یعنی شرط خاص هیچ‌وقت اجرا نمی‌شود. راه‌حل: از سخت‌گیرانه‌ترین شرط شروع کن.

۵) حلقه‌ی while که هیچ‌وقت تمام نمی‌شود

Section titled “۵) حلقه‌ی while که هیچ‌وقت تمام نمی‌شود”

مثال ۸. راه‌حل: قبل از نوشتن while از خودت بپرس «چه چیزی داخل حلقه شرط را غلط می‌کند؟». و یادت باشد Ctrl+C همیشه راه فرار است.

۶) فراموش کردن اینکه range(1, 10) خود ۱۰ را ندارد

Section titled “۶) فراموش کردن اینکه range(1, 10) خود ۱۰ را ندارد”

راه‌حل: برای ۱ تا ۱۰ بنویس range(1, 11).

تمرینآسان

برنامه‌ای بنویس که یک عدد بگیرد و بگوید زوج است یا فرد. (راهنما: % در درس قبل.)

دیدن جواب
even.py
n = int(input("یک عدد: "))
if n % 2 == 0:
print(f"{n} زوج است")
else:
print(f"{n} فرد است")
صفحه (جواب: 7)
یک عدد: 7
7 فرد است
تمرینمتوسط

تمرین اصلی (FizzBuzz، سؤال مصاحبه‌ی معروف): برای عددهای ۱ تا ۱۵، اگر عدد بر ۳ و ۵ هر دو بخش‌پذیر بود FizzBuzz، اگر فقط بر ۳ Fizz، اگر فقط بر ۵ Buzz، وگرنه خود عدد را چاپ کن.

دیدن جواب
fizz.py
for n in range(1, 16):
if n % 15 == 0:
print("FizzBuzz")
elif n % 3 == 0:
print("Fizz")
elif n % 5 == 0:
print("Buzz")
else:
print(n)
خروجی (در یک خط نوشته شده)
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz

نکته‌ی کلیدی ترتیب است: اگر n % 3 == 0 را اول می‌گذاشتی، ۱۵ فقط Fizz می‌شد. بخش‌پذیری بر ۳ و ۵ هر دو یعنی بخش‌پذیری بر ۱۵.

تمرینسخت

جدول ضرب ۱ تا ۳ را با دو حلقه‌ی تو در تو چاپ کن، هر سطر در یک خط. (راهنما: print(..., end=" ") به‌جای رفتن به خط بعد، دو فاصله چاپ می‌کند؛ و یک print() خالی فقط به خط بعد می‌رود.)

دیدن جواب
table.py
for i in range(1, 4):
for j in range(1, 4):
print(f"{i}×{j}={i*j}", end=" ")
print()
خروجی
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) سه بار اجرا می‌شود و در هر بار، حلقه‌ی درونی (j) سه بار کامل. print() آخر داخل حلقه‌ی بیرونی ولی بیرون از درونی است (تورفتگی‌اش را ببین)، پس بعد از هر سطر یک بار اجرا می‌شود.

آزمونک
  1. بلوک یک if در پایتون با چه چیزی مشخص می‌شود؟

  2. range(2, 6) چه عددهایی می‌دهد؟

  3. break چه می‌کند؟

  4. کی while بهتر از for است؟

  5. خطای «expected an indented block» یعنی…

  6. برنامه در حلقه‌ی بی‌پایان گیر کرده. چه کنی؟

  • if شرط: + بلوک تورفته؛ elif برای شاخه‌های بعدی؛ else برای «هیچ‌کدام». فقط اولین شاخه‌ی درست اجرا می‌شود.
  • در پایتون دونقطه و چهار فاصله‌ی تورفتگی جزو قواعد زبان‌اند.
  • for x in دنباله: روی range، متن و (بعداً) لیست و فایل؛ range(a, b) تا قبل از b.
  • while شرط: تا وقتی شرط درست است؛ مطمئن شو بالاخره غلط می‌شود؛ Ctrl+C راه فرار.
  • break حلقه را تمام می‌کند؛ continue دور بعد.
  • الگوی «متغیر را قبل از حلقه صفر کن، داخل حلقه اضافه کن» برای جمع و شمارش.
برگه‌ی تقلب این درس
دستورکاری که می‌کند
if x > 0:شرط (بلوک بعدی تورفته)
elif x == 0:شاخه‌ی بعدی
else:هیچ‌کدام
for i in range(5):۰ تا ۴
for ch in "متن":هر حرف
while n < 10:تا وقتی شرط درست است
break / continueتمام کردن حلقه / دور بعد
while True: ... breakتکرار تا رسیدن به شرط خروج
print(x, end=" ")چاپ بدون رفتن به خط بعد