حلقه while
حلقه for وقتی خوب است که از قبل بدانید چند بار باید
تکرار کنید. ولی خیلی وقتها نمیدانید: تا وقتی کاربر خسته شود، تا
وقتی جواب درست پیدا شود، تا وقتی فایل تمام شود. اینجا جای
while است.
۱. اولین while
while یعنی «تا وقتی که». شرطی میگیرد و تا وقتی آن شرط درست
است، بدنهاش را تکرار میکند.
# A 'while' repeats as long as its condition is True.
# Something inside the loop MUST eventually make the condition False,
# otherwise the program never stops (an "infinite loop").
x = 0
while x < 10:
x += 1 # without this line the loop would never end
print(x)
شمارش با while: نمونه 01_first_while.py
شرح مثال
- سه چیز همیشه لازم است: مقدار اولیه پیش از حلقه، شرط در خط
while، و تغییر داخل بدنه. - اگر خط
x += 1نبود، شرط همیشه درست میماند و برنامه هرگز تمام نمیشد. - شرط پیش از هر دور بررسی میشود. اگر از همان اول نادرست باشد، بدنه حتی یک بار هم اجرا نمیشود.
۲. حلقه بیپایان
حلقه بیپایان یعنی حلقهای که شرطش هرگز نادرست نمیشود. برنامه ظاهراً هنگ میکند یا بینهایت خط چاپ میکند. برای متوقف کردنش در ترمینال کلیدهای Ctrl + C را بزنید. این کلید را در همین مرحله یاد بگیرید، چون در هفته اول کار با while چند بار لازمتان میشود.
سه علت رایج حلقه بیپایان:
- یادتان رفته متغیر شرط را داخل حلقه تغییر دهید.
- خط تغییردهنده را اشتباهاً بیرون حلقه گذاشتهاید، یعنی تورفتگیاش غلط است.
- شرط را برعکس نوشتهاید، مثلاً
x > 0در حالی کهxدارد بزرگتر میشود.
۳. for یا while، کدام
# Use 'for' when you know in advance how many turns you need.
for i in range(1, 6):
print(i, end=' ')
print()
# Use 'while' when the number of turns depends on something that happens
# during the loop.
i = 1
while i <= 5:
print(i, end=' ')
i += 1
print()
یک کار، دو روش: نمونه 02_while_vs_for.py
| وقتی که | حلقه مناسب | مثال |
|---|---|---|
| تعداد تکرار از قبل معلوم است | for | چاپ ۱ تا ۱۰۰، پیمایش یک لیست |
| تعداد تکرار معلوم نیست | while | تا وقتی کاربر exit بزند، تا وقتی رمز درست شود |
در مثال بالا هر دو یک خروجی دارند، ولی for کوتاهتر و
کمخطرتر است، چون شمارنده را خودش مدیریت میکند و امکان حلقه بیپایان
ندارد. قانون ساده: اگر میشود با for نوشت، با
for بنویسید.
۴. while True و break
الگویی که در برنامههای واقعی بیش از همه دیده میشود این است: حلقه را
عمداً بیپایان میسازیم و با break از وسطش بیرون میپریم.
مقداری که باعث خروج میشود را نگهبان مینامند.
# A "sentinel" is a special value that means "stop".
# Here the sentinel is the word 'exit'.
total = 0
while True: # loop for ever ...
user_input = input('Enter a number (or "exit"): ')
if user_input == 'exit':
break # ... until break jumps out of it
number = float(user_input)
total += number
print('Sum is:', total)
print('Final sum:', total)
جمع تا رسیدن نگهبان: نمونه 03_sentinel_sum.py
Enter a number (or "exit"): 5 Sum is: 5.0 Enter a number (or "exit"): 3 Sum is: 8.0 Enter a number (or "exit"): exit Final sum: 8.0
شرح مثال
while Trueیعنی شرط همیشه درست است، پس حلقه به خودی خود تمام نمیشود.breakبلافاصله از حلقه بیرون میپرد و اجرا از اولین خط بعد از حلقه ادامه مییابد.- بررسی نگهبان باید پیش از تبدیل نوع باشد. اگر اول
float(user_input)را بنویسید، کلمه exit برنامه را خراب میکند. - چرا این الگو بهتر از گذاشتن شرط در خود
whileاست؟ چون باید ورودی را بگیریم تا بتوانیم بررسیاش کنیم، و گرفتن ورودی وسط حلقه اتفاق میافتد، نه پیش از آن.
۵. دستور continue
break از حلقه بیرون میپرد، ولی continue فقط سایر موارد نیزین دور را رد میکند و به بالای حلقه برمیگردد.
# 'continue' skips the REST of the current turn and goes back to the top.
# Here the odd numbers are simply ignored.
total = 0
while True:
user_input = input('Enter a number (or "exit"): ')
if user_input == 'exit':
break
number = int(user_input)
if number % 2 != 0:
print('Odd number ignored.')
continue # go back to the input() line
total += number
print('Sum is:', total)
رد کردن اعداد فرد: نمونه 04_continue.py
| دستور | اثرش |
|---|---|
break | خروج کامل از حلقه |
continue | رد کردن بقیه این دور و رفتن به دور بعد |
continue بیشتر برای «فیلتر کردن» به کار میرود: چیزهایی که برای مسئله ما کاربردی ندارند را زود رد میکنیم تا کد اصلی داخل تودرتویی عمیق نیفتد. مقایسه کنید با نوشتن یک else بزرگ که همه کد اصلی را داخلش میبرد.
۶. میانگین در حال اجرا
# Two accumulators: the total and how many numbers were entered.
total = 0
counter = 0
while True:
user_input = input('Enter a number (or "exit"): ')
if user_input == 'exit':
break
number = float(user_input)
total += number
counter += 1
print('Average is:', total / counter)
# After the loop, counter may still be 0 - never divide by it blindly.
if counter == 0:
print('No number was entered.')
else:
print('Final average:', total / counter)
میانگین در حال اجرا: نمونه 05_running_average.py
داخل حلقه، تقسیم بر counter بیخطر است چون همان بالا یکی
اضافه شده و حتماً بزرگتر از صفر است. ولی بعد از حلقه چنین تضمینی نداریم:
اگر کاربر همان اول exit بزند، شمارنده صفر میماند. برای همین شرط پایانی
لازم است.
۷. اعتبارسنجی ورودی
این کاربردیترین الگوی این فصل است. تا وقتی کاربر جواب معتبر ندهد، سؤال را تکرار میکنیم.
# A very common use of 'while': keep asking until the answer makes sense.
while True:
user_input = input('Enter your age (1-120): ')
if not user_input.isdigit():
print('Please type digits only.')
continue
age = int(user_input)
if age < 1 or age > 120:
print('The age must be between 1 and 120.')
continue
break # the value is valid, leave the loop
print('Your age is', age)
اعتبارسنجی: نمونه 06_input_validation.py
Enter your age (1-120): abc Please type digits only. Enter your age (1-120): 500 The age must be between 1 and 120. Enter your age (1-120): 25 Your age is 25
شرح مثال
- ساختار: هر بررسی که رد شود، پیام میدهد و
continueمیکند. اگر همه بررسیها رد شدند، بهbreakمیرسیم. isdigit()از فصل سوم اینجا حیاتی است: پیش ازint()مطمئن میشویم ورودی واقعاً رقم است. بدون آن، تایپ یک حرف برنامه را خراب میکند.- ترتیب مهم است: اول بررسی نوع، بعد تبدیل، بعد بررسی بازه.
- در فصل نوزدهم راه دیگری برای همین کار میبینید که
tryنام دارد و برای حالتهای پیچیدهتر مناسبتر است.
۸. بازی حدس عدد
# A tiny game: the program knows a number, the player has to find it.
SECRET = 16
tries = 0
while True:
user_input = input('Enter a number: ')
guess = int(user_input)
tries += 1
if guess < SECRET:
print('The number is greater!')
elif guess > SECRET:
print('The number is smaller!')
else:
print(f'You win! You needed {tries} tries.')
break
حدس عدد: نمونه 07_guess_the_number.py
Enter a number: 10 The number is greater! Enter a number: 20 The number is smaller! Enter a number: 16 You win! You needed 3 tries.
این اولین بازی شماست. هنوز کامل نیست: عدد ثابت است و
بعد از یک بار بازی، دیگر جالب نیست. در فصل شانزدهم با
random عدد را تصادفی میکنیم و در فصل بیستم نسخه کاملش را
با محدودیت تعداد حدس میسازیم.
۹. تشخیص عدد اول
# A prime number is only divisible by 1 and by itself.
# As soon as we find one divisor we can stop looking -> 'break'.
user_input = input('Enter your number: ')
number = int(user_input)
# 0, 1 and the negative numbers are NOT prime, so we handle them separately.
if number < 2:
is_prime = False
else:
is_prime = True
for i in range(2, number):
if number % i == 0:
is_prime = False
break # no need to test the remaining divisors
if is_prime:
print("It's prime!")
else:
print("It's not prime.")
عدد اول: نمونه 08_is_prime.py
شرح مثال
- الگوی مهمی اینجا هست: یک متغیر پرچم به نام
is_primeکه باTrueشروع میشود و به محض پیدا شدن مقسومعلیه،Falseمیشود. breakبعد از پیدا شدن اولین مقسومعلیه، بقیه حلقه را بیفایده میداند و بیرون میپرد. برای عدد یک میلیون این یعنی صرفهجویی عظیم.breakدر حلقهforهم درست مثلwhileکار میکند.
نسخه اصلی این برنامه شرط number < 2 را نداشت. نتیجه
این بود که عدد ۱ و عدد صفر و حتی اعداد منفی «اول» اعلام میشدند،
چون حلقه range(2, 1) اصلاً اجرا نمیشد و پرچم
True باقی میماند. درس: همیشه حالتهای مرزی را جدا
بررسی کنید. حلقهای که هیچ دوری نمیزند، خطر پنهان دارد.
۱۰. بلوک else حلقه
این یکی از ویژگیهای عجیب و کمشناخته پایتون است: حلقه میتواند
else داشته باشد. آن بلوک وقتی اجرا میشود که حلقه
به طور طبیعی تمام شود، یعنی با break
قطع نشده باشد.
# A loop may have an 'else' block. It runs only when the loop finished
# normally, that is when it was NOT stopped by a 'break'.
number = int(input('Enter a number: '))
for i in range(2, number):
if number % i == 0:
print(f'{number} is divisible by {i}')
break
else:
# reached only when no divisor was found
print(f'{number} is prime!')
else حلقه: نمونه 09_while_else.py
مقایسه کنید با نسخه قبلی: اینجا دیگر متغیر پرچم ضرورتی ندارد. اگر حلقه مقسومعلیهی پیدا کند، break میزند و else اجرا نمیشود. اگر تا آخر برود و چیزی پیدا نکند، else اجرا میشود.
بهتر بود اسمش nobreak بود، نه else. چون
معنایش «اگر حلقه شکسته نشد» است، نه «در غیر این صورت». طراح پایتون
هم بعدها گفته که این نامگذاری اشتباه بوده است. با این حال، الگوی
«جستوجو کن و اگر پیدا نشد کاری بکن» را واقعاً تمیز مینویسد.
۱۱. باز کردن یک عدد رقم به رقم
# Taking a number apart digit by digit is a classic 'while' exercise.
user_input = input('Enter a positive number: ')
number = int(user_input)
digit_count = 0
digit_sum = 0
while number > 0:
digit = number % 10 # the last digit
digit_sum += digit
digit_count += 1
number = number // 10 # remove the last digit
print('Number of digits:', digit_count)
print('Sum of the digits:', digit_sum)
ارقام یک عدد: نمونه 10_digits_of_number.py
Enter a positive number: 4728 Number of digits: 4 Sum of the digits: 21
شرح مثال
عدد ۴۷۲۸ را دنبال کنیم:
| دور | number | number % 10 | number // 10 |
|---|---|---|---|
| ۱ | ۴۷۲۸ | ۸ | ۴۷۲ |
| ۲ | ۴۷۲ | ۲ | ۴۷ |
| ۳ | ۴۷ | ۷ | ۴ |
| ۴ | ۴ | ۴ | ۰ |
وقتی number به صفر رسید، شرط حلقه نادرست میشود و کار تمام
است. این همان ترکیب % و // فصل دوم است که حالا
داخل یک حلقه قدرت واقعیاش را نشان میدهد. با همین الگو میشود عدد را
برعکس کرد، که یکی از تمرینهای این فصل است.
پوشه S08-while-loops شامل نمونههای
01_first_while.py تا 10_digits_of_number.py.
خلاصه فصل
| ابزار | وظیفه آن |
|---|---|
while شرط: | تکرار تا وقتی شرط درست است |
| سه جزء لازم | مقدار اولیه، شرط، تغییر داخل بدنه |
| حلقه بیپایان | شرطی که هرگز نادرست نمیشود. توقف با Ctrl + C |
while True: با break | پرکاربردترین الگو در برنامههای تعاملی |
break | خروج فوری از حلقه |
continue | رد کردن بقیه دور جاری |
| نگهبان | مقدار خاصی مثل exit که یعنی «تمام» |
| حلقه اعتبارسنجی | تا وقتی ورودی معتبر نشده، دوباره بپرس |
| متغیر پرچم | متغیر بولی که نتیجه جستوجو را نگه میدارد |
else حلقه | فقط وقتی حلقه بدون break تمام شود |
تمرینهای فصل هشت
- تا وقتی کاربر
exitنزده عدد بگیرید و در پایان بزرگترین را چاپ کنید. - یک پرسش رمز بنویسید که به کاربر سه فرصت بدهد.
- عدد بگیرید تا
exit، و بگویید چند تا مثبت و چند تا منفی بودند. - یک عدد بگیرید و برعکسش کنید، مثلاً
123به321، فقط با//و%. - بازی حدس عدد را طوری بنویسید که کامپیوتر عدد را تصادفی انتخاب کند. کافی است
import randomکنید؛ در فصل شانزدهم کاملش را میبینید. - یک عدد بگیرید و همه مقسومعلیههایش را چاپ کنید.
- دو عدد بگیرید و بزرگترین مقسومعلیه مشترکشان را با یک حلقه
whileپیدا کنید. - منوی فصل پنجم را داخل یک حلقه بگذارید تا تا وقتی کاربر گزینه صفر را نزده تکرار شود.