elif و شرطهای تودرتو
دنیای واقعی دو حالته نیست. نمره دانشآموز چهار درجه دارد، منوی برنامه پنج گزینه، و روزهای هفته هفت تا. این فصل درباره انتخاب از میان چند حالت است.
۱. دستور elif
کلمه elif کوتاهشده else if است، یعنی «وگرنه
اگر». با آن میشود هر تعداد شاخه پشت سر هم گذاشت.
# 'elif' means "else if". Python tests the branches from top to bottom and
# runs ONLY the first one whose condition is True.
user_input = input('Enter a number (1-7): ')
if user_input == '1':
print('Shanbe')
elif user_input == '2':
print('Yekshanbe')
elif user_input == '3':
print('Doshanbe')
elif user_input == '4':
print('Seshanbe')
elif user_input == '5':
print('Chaharshanbe')
elif user_input == '6':
print('Panjshanbe')
elif user_input == '7':
print('Jome')
else:
print('Error: the number must be between 1 and 7')
روز هفته: نمونه 01_elif_days.py
Enter a number (1-7): 3 Doshanbe
شرح مثال
- ساختار همیشه این است: یک
if، بعد هر تعدادelif، و در انتها یکelseکه اختیاری است. elseآخر همیشه ارزش دارد. بدون آن، اگر کاربر عدد ۹ وارد کند، برنامه هیچ چیزی چاپ نمیکند و کاربر فکر میکند خراب شده است.- اینجا ورودی با رشته مقایسه شده است، یعنی
'1'با گیومه. چونinputرشته میدهد و تبدیلش نکردهایم. این کار عمدی است: اگر کاربر حرف تایپ کند،int()برنامه را خراب میکرد ولی اینطور فقط به شاخهelseمیرود.
۲. فقط اولین شاخه درست اجرا میشود
این مهمترین قانون elif است. پایتون شرطها را از بالا به
پایین امتحان میکند و به محض اینکه یکی درست شد، بلوکش را اجرا میکند و
بقیه را کاملاً نادیده میگیرد.
# Three possible outcomes -> if / elif / else.
user_input = input('Enter a number: ')
number = float(user_input)
if number > 0:
print('Positive')
elif number < 0:
print('Negative')
else:
print('Zero')
مثبت، منفی یا صفر: نمونه 02_elif_sign.py
اگر سه if جداگانه بنویسید، پایتون هر سه را بررسی میکند و
ممکن است چند تایشان اجرا شوند. با elif فقط یکی اجرا
میشود و بقیه حتی بررسی هم نمیشوند. وقتی حالتها
متقابلاً ناسازگارند (عدد نمیتواند هم مثبت باشد هم
منفی)، همیشه elif درستتر و سریعتر است.
۳. ترتیب شاخهها مهم است
# The ORDER of the branches matters. We test from the highest score downwards,
# so when we reach 'elif score >= 17' we already know the score is below 20.
user_input = input('Enter the score (0-20): ')
score = float(user_input)
if score > 20 or score < 0:
print('Invalid score')
elif score >= 17:
print('A - Excellent')
elif score >= 14:
print('B - Good')
elif score >= 10:
print('C - Passed')
else:
print('F - Failed')
نمره به حرف: نمونه 03_elif_grades.py
شرح مثال
- شرطها از بالا به پایین از سختگیرترین به آسانترین چیده شدهاند. وقتی به
score >= 14میرسیم، مطمئنیم نمره زیر ۱۷ است، چون اگر بالای ۱۷ بود شاخه قبلی گرفته بودش. برای همین ضرورتی ندارد بنویسیم14 <= score < 17. - اگر ترتیب را برعکس کنید و
score >= 10را اول بگذارید، نمره ۱۹ همCمیگیرد و کل برنامه غلط میشود، بدون اینکه هیچ خطایی ببینید. - شاخه اول اعتبارسنجی است: اول ورودی نامعتبر را رد میکنیم، بعد سراغ حالتهای واقعی میرویم. این الگو در برنامهنویسی حرفهای بسیار رایج است.
۴. ماشینحساب
این مثال هم elif دارد و هم یک if تودرتو، و
نمونه خوبی است از اینکه هر دو ابزار در یک برنامه کنار هم مینشینند.
# A simple calculator: two numbers and one operator.
num1 = float(input('Enter number 1: '))
num2 = float(input('Enter number 2: '))
operator = input('Enter the sign (+ - * / **): ')
if operator == '+':
result = num1 + num2
print(result)
elif operator == '-':
result = num1 - num2
print(result)
elif operator == '*':
result = num1 * num2
print(result)
elif operator == '/':
# Dividing by zero would crash the program, so we check it first.
if num2 == 0:
print('Error: division by zero!')
else:
result = num1 / num2
print(result)
elif operator == '**':
result = num1 ** num2
print(result)
else:
print('Error: unknown operator!')
ماشینحساب: نمونه 04_calculator.py
Enter number 1: 8 Enter number 2: 0 Enter the sign (+ - * / **): / Error: division by zero!
در فایل اصلی دوره، بررسی تقسیم بر صفر وجود نداشت. اگر کاربر مخرج را
صفر میداد، برنامه با خطای ZeroDivisionError کاملاً
متوقف میشد. قانون کلی: هر جا تقسیم دارید، به مخرج صفر فکر کنید.
این یکی از سه چهار خطایی است که در تمام دنیا برنامهها را از کار
میاندازد.
۵. شرط تودرتو
شرط تودرتو یعنی یک if داخل بلوک یک if دیگر.
وقتی به کار میآید که سؤال دوم فقط در صورتی معنا دارد که جواب سؤال اول
مثبت باشد.
# A nested 'if' is an 'if' placed inside the block of another 'if'.
# Here the password is only asked about when the username is correct.
username = input('Enter the username: ')
password = input('Enter the password: ')
if username == 'admin':
if password == '123456':
print('Welcome', username)
else:
print('The password is incorrect!')
else:
print('The username is incorrect!')
ورود تودرتو: نمونه 05_nested_login.py
نسخه دوم همین برنامه یک قدم جلوتر میرود: رمز را اصلاً نمیپرسد مگر اینکه نام کاربری درست باشد.
# Same program, but the password is only READ when the username is correct.
# This is the real advantage of nesting: we skip work we do not need.
USERNAME = 'admin'
PASSWORD = '123456'
username_input = input('Enter username: ')
if username_input == USERNAME:
password_input = input('Enter password: ')
if password_input == PASSWORD:
print('Welcome!')
else:
print('Password error!')
else:
print('Username error!')
ورود تودرتو، نسخه دوم: نمونه 06_nested_login2.py
شرح مثال
- هر سطح تودرتویی، چهار فاصله دیگر تورفتگی میگیرد.
ifداخلی هشت فاصله از ابتدای خط فاصله دارد. - هر
elseبهifهمتراز خودش تعلق دارد. تورفتگی است که این را مشخص میکند، پس در شرطهای تودرتو باید خیلی مراقب باشید. - مزیت واقعی نسخه دوم این است که کار غیرلازم انجام نمیدهد. اگر نام کاربری غلط است، چرا اصلاً رمز بپرسیم.
جالب است بدانید سایتهای واقعی عمداً برعکس این کار را میکنند و همیشه پیام یکسان «نام کاربری یا رمز اشتباه است» میدهند. اگر برنامه بگوید «نام کاربری اشتباه است»، مهاجم میفهمد کدام نامهای کاربری وجود دارند و نصف کار را انجام داده است.
۶. elif یا تودرتو، کدام
| حالت | ابزار درست | مثال |
|---|---|---|
| چند حالت همرده و ناسازگار | elif | روز هفته، نمره، منو |
| سؤال دوم وابسته به جواب سؤال اول | تودرتو | اول نام کاربری، بعد رمز |
قانون عملی: اگر تودرتویی از سه سطح بیشتر شد، معمولاً یعنی طراحی را باید
عوض کرد. کد عمیقاً تودرتو خوانده نمیشود. در فصل یازدهم با تابع و در
فصل هشتم با continue راههایی برای صاف کردن این تودرتوییها
میبینید.
۷. عملگر شرطی یکخطی
وقتی کل کار if و else فقط انتخاب بین
دو مقدار است، پایتون شکل یکخطی زیبایی دارد.
# When an if/else only chooses between two VALUES, Python offers a one-line form:
# value_if_true if condition else value_if_false
age = int(input('Enter your age: '))
status = 'adult' if age >= 18 else 'minor'
print(status)
# The long version does exactly the same thing:
if age >= 18:
status = 'adult'
else:
status = 'minor'
print(status)
# It is often used directly inside a print():
number = 7
print(f'{number} is', 'even' if number % 2 == 0 else 'odd')
عملگر شرطی: نمونه 08_ternary.py
Enter your age: 20 adult adult 7 is odd
شرح مثال
- ترتیب نوشتن کمی عجیب است: اول مقدار حالت درست، بعد شرط، بعد مقدار حالت نادرست. آن را اینطور بخوانید: «adult، اگر سن بالای ۱۸ است، وگرنه minor».
- این عملگر فقط برای انتخاب مقدار است، نه برای اجرای چند دستور. اگر داخل هر شاخه بیش از یک کار دارید، شکل بلند را بنویسید.
- در فصل بیست و پنجم میبینید که همین عملگر داخل درک لیستی خیلی به کار میآید.
۸. دستور match
از پایتون ۳٫۱۰ به بعد، ساختار تازهای اضافه شده که وقتی همه شاخهها
یک مقدار واحد را با چیزهای مختلف مقایسه میکنند،
تمیزتر از زنجیره elif است.
# From Python 3.10 on, 'match ... case' is a clean alternative to a long
# chain of elif branches that all compare the SAME value.
user_input = input('Enter a number (1-7): ')
match user_input:
case '1':
print('Shanbe')
case '2':
print('Yekshanbe')
case '3':
print('Doshanbe')
case '4':
print('Seshanbe')
case '5':
print('Chaharshanbe')
case '6' | '7': # '|' means "or": one branch for two values
print('Weekend')
case _: # '_' is the default branch, like 'else'
print('Error: the number must be between 1 and 7')
روز هفته با match: نمونه 09_match_days.py
شرح مثال
- بعد از
matchمقداری میآید که میخواهیم بررسیاش کنیم، و هرcaseیک حالت ممکن است. - علامت
|یعنی «یا»: یک شاخه برای چند مقدار. - زیرخط
_شاخه پیشفرض است و نقشelseرا دارد. اگر ننویسیدش و هیچ حالتی جور در نیاید، هیچ اتفاقی نمیافتد. matchفقط وقتی به درد میخورد که همه شاخهها یک متغیر واحد را بررسی کنند. برای شرطهای متفاوت مثلscore >= 17باید همانelifرا به کار ببرید.
۹. منو با match
# A menu is the classic use of match/case.
print('1) New file')
print('2) Open file')
print('3) Save file')
print('0) Exit')
choice = input('Enter the number: ')
match choice:
case '1':
print('Creating a new file...')
case '2':
print('Opening a file...')
case '3':
print('Saving the file...')
case '0':
print('Goodbye!')
case _:
print('Unknown option.')
منو: نمونه 10_match_menu.py
منو کلاسیکترین کاربرد match است. فعلاً این برنامه یک بار
اجرا میشود و تمام. در فصل هشتم آن را داخل یک حلقه while
میگذاریم تا منو تا وقتی کاربر گزینه خروج را نزده تکرار شود، و آن وقت
تازه شبیه یک برنامه واقعی میشود.
۱۰. یک برنامه کوچک ترکیبی
# If the number is odd, make it even by adding 1, then print its square.
user_input = input('Please enter a number: ')
number = int(user_input)
if number % 2 != 0:
number += 1
result = number ** 2
print('Result:', result)
زوج کردن و توان دو: نمونه 11_make_it_even.py
Please enter a number: 7 Result: 64
اینجا if بدون else آمده است و کاملاً درست است. وقتی عدد زوج باشد، هیچ کاری ضرورتی ندارد. این الگو، یعنی «اگر لازم بود اصلاحش کن و بعد ادامه بده»، در برنامههای واقعی بسیار دیده میشود.
پوشه S05-elif-and-nested-conditionals شامل نمونههای
01_elif_days.py تا 11_make_it_even.py.
خلاصه فصل
| ابزار | وظیفه آن |
|---|---|
elif | شاخه بعدی. هر تعداد که بخواهید |
| ترتیب شاخهها | فقط اولین شاخه درست اجرا میشود، پس ترتیب حیاتی است |
else پایانی | گرفتن حالتهای پیشبینینشده. تقریباً همیشه بنویسیدش |
| شرط تودرتو | وقتی سؤال دوم فقط با جواب مثبت سؤال اول معنا دارد |
a if cond else b | انتخاب یکخطی بین دو مقدار |
match و case | جایگزین تمیز زنجیره elif وقتی همه یک متغیر را میسنجند |
case _: | شاخه پیشفرض در match |
| تقسیم بر صفر | هر جا تقسیم هست، مخرج صفر را بررسی کنید |
تمرینهای فصل پنج
- شماره ماه (۱ تا ۱۲) را بگیرید و بگویید مربوط به کدام فصل است.
- یک نمره بگیرید و با
elifحرف معادلش را چاپ کنید. - یک منوی چهار گزینهای بنویسید و به هر گزینه واکنش نشان دهید. از
matchاستفاده کنید. - وزن و قد را بگیرید، شاخص توده بدنی را با
weight / height ** 2حساب کنید و دستهاش را بگویید: زیر ۱۸٫۵، بین ۱۸٫۵ و ۲۵، بین ۲۵ و ۳۰، بالای ۳۰. - سه عدد بگیرید و از کوچک به بزرگ مرتب چاپشان کنید، فقط با
ifوelifوelse. - ماشینحساب را طوری کامل کنید که
%و//را هم پشتیبانی کند. - تمرین اول فصل چهار را با عملگر شرطی یکخطی بازنویسی کنید.
- یک کاراکتر بگیرید و بگویید حرف صدادار است، بیصداست یا رقم.