تکرار، قلب اتوماسیون
پایتون دو حلقه دارد: while که «تا وقتی شرط درست است» تکرار میکند، و for که «روی اعضای یک مجموعه» میچرخد. قاعدهی انتخاب ساده است: اگر تعداد یا مجموعهی اعضا را میدانید، for؛ اگر پایان به رویدادی بستگی دارد (ورودی درست کاربر، رسیدن به هدف)، while.
while و اعتبارسنجی ورودی
while True:
text = input("تعداد تخته (۱ تا ۱۰۰): ")
if text.isdigit() and 1 <= int(text) <= 100:
qty = int(text)
break # خروج از حلقه
print("عدد معتبر وارد کنید.")
print(f"{qty} تخته ثبت شد")
الگوی while True + break رایجترین راه برای «تا ورودی درست نیامده، دوباره بپرس» است. اگر حلقهای بیپایان شد، در ترمینال Ctrl+C آن را متوقف میکند.
عملگر walrus
از Python 3.8 عملگر := اجازه میدهد وسط یک عبارت، مقداری را به متغیر نسبت دهید. برای حلقههایی که ورودی میخوانند بسیار تمیز است:
while (cmd := input("> ").strip()) != "q":
print(f"دستور: {cmd}")
for و range
for روی هر چیز «پیمایشپذیر» (iterable) کار میکند: لیست، رشته، دیکشنری، فایل و… . برای تکرار عددی از range استفاده میشود که عدد پایانی را شامل نمیشود:
| عبارت | اعداد تولیدشده |
|---|---|
range(5) | 0, 1, 2, 3, 4 |
range(1, 6) | 1, 2, 3, 4, 5 |
range(0, 20, 5) | 0, 5, 10, 15 |
range(10, 0, -3) | 10, 7, 4, 1 |
prices = [8_500_000, 12_000_000, 4_200_000]
total = 0
for p in prices:
if p < 5_000_000:
continue # این یکی را رد کن و برو سراغ بعدی
total += p
print(f"{total:,}") # 20,500,000
else روی حلقه: کمترشناختهشده اما مفید
حلقههای for و while میتوانند بخش else داشته باشند که فقط اگر حلقه بدون break تمام شود اجرا میشود. کاربرد کلاسیک: جستوجو.
codes = ["KSH-101", "TBZ-220", "MSH-310"]
target = "ISF-500"
for code in codes:
if code == target:
print("پیدا شد")
break
else:
print("سفارشی با این کد وجود ندارد")
بدون else باید یک متغیر پرچم (found = False) تعریف میکردید. نام else اینجا کمی گمراهکننده است؛ آن را در ذهن «nobreak» بخوانید.
نکتههایی که کمتر کسی میداند
- متغیر حلقهی for بعد از حلقه باقی میماند و آخرین مقدار را دارد؛ اما اگر حلقه اصلاً اجرا نشود (لیست خالی)، تعریف نشده است و NameError میگیرید.
- حذف عضو از لیستی که روی آن for میزنید، عضوها را جا میاندازد. روی یک کپی بچرخید (
for x in items[:]:) یا لیست جدید بسازید. rangeلیست نمیسازد و حافظهی ثابتی دارد؛range(10**12)فوری ساخته میشود و10**11 in range(10**12)هم بدون پیمایش جواب میدهد.breakفقط از درونیترین حلقه خارج میشود؛ برای خروج از دو حلقهی تودرتو، آنها را در یک تابع بگذارید وreturnکنید.- برای شمارش معکوس،
reversed(range(5))خواناتر ازrange(4, -1, -1)است و خطای یکیکمیکیزیاد ندارد.