Faragiri

همهٔ زبان‌ها

آموزش ساختارهای کنترلیسازه‌های اصلی برنامه

یک حلقه که دنبال اولین ردیف تسویه‌نشده می‌گردد، و شاخه پیدا نشد که بدون هیچ پرچمی نوشته می‌شود. جای تورفتگی تعیین می‌کند کدام است.

۴بخش
۳دقیقه خواندن
۴عمق

شاخه‌ای که پرچم ندارد

چه چیزی تعیین می‌کند else یک حلقه اجرا شود

این else مال حلقه است و نه مال if داخلش، و تنها پرسشش این است که حلقه زودتر ترک شد یا نه.

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

فهرست خالی هم شاخه دوم را می‌گیرد، که معمولا درست است و گاهی نه: چیزی گشته نشد، و else نمی‌تواند این را از گشتن همه‌جا تشخیص دهد.

پایتون یک شاخه دارد که تقریباً هیچ‌کس نمی‌نویسد و دقیقاً برای همان کاری ساخته شده که همه با یک متغیر پرچم انجامش می‌دهند: else پس از for. فقط وقتی اجرا می‌شود که حلقه با break ترک نشده باشد.

  • for radif in radifha:
  • if radif["mande"] > 0:
  • chap(radif["shomare"]); break
  • else:
  • chap("hame radifha taswie shode")

روی یک فهرست هفت ردیفی که ردیف چهارم بدهکار است، شماره همان ردیف چاپ می‌شود و else اصلا اجرا نمی‌شود. روی فهرستی که همه‌اش تسویه است، حلقه تا ته می‌رود و پیام دوم چاپ می‌شود. هیچ متغیر peyda_shod در کار نیست و هیچ‌جا هم لازم نمی‌شود.

تنها چیزی که باید درست باشد تورفتگی است: else هم‌تراز for نوشته می‌شود و نه هم‌تراز if. هم‌تراز if بنویسیدش و برنامه بدون هیچ خطایی معنای دیگری پیدا می‌کند، یعنی برای هر ردیف تسویه‌شده یک بار چاپ می‌کند. این تنها ساختاری در زبان است که کلمه‌اش با کاری که می‌کند نمی‌خواند؛ اگر به‌جای else اسمش nobreak بود کسی اشتباه نمی‌گرفتش.

فهرست خالی هم شاخه دوم را می‌گیرد

روی یک فهرست خالی، بدنه حلقه یک بار هم اجرا نمی‌شود و else اجرا می‌شود. یعنی همان پیام «همه تسویه شده» برای فایلی چاپ می‌شود که اصلا سطری نداشت. معمولا همین درست است و گاهی فاجعه، و تفاوتش را حلقه نمی‌داند: از دید else، هیچ نگشتن و همه‌جا گشتن یک شکل دارند. اگر این تفاوت مهم است، پیش از حلقه خالی بودن را جدا بررسی کنید.

سه چیزی که یک حلقه را ناخوانا می‌کنند

اول، تودرتویی بیش از دو سطح. سطح سوم تقریبا همیشه یعنی حلقه داخلی باید تابع شود، و اسم آن تابع همان چیزی است که عوض کردن شکل، بدون عوض کردن رفتار دنبالش است. دوم، continue در انتهای بدنه، که هیچ کاری نمی‌کند جز اینکه خواننده را برمی‌گرداند بالا تا مطمئن شود. سوم، شرطی که هم فیلتر می‌کند و هم کار انجام می‌دهد؛ اگر شرط طولانی است، خودش یک تابع با یک نام است.

حلقه‌ای که فقط دنبال یک عضو می‌گردد معمولا اصلا لازم نیست نوشته شود. next((r for r in radifha if r["mande"] > 0), None) همان کار را در یک سطر می‌کند و مقدار پیش‌فرض جای شاخه پیدا نشد را می‌گیرد. کی این کار درست است و کی باید ساختار داده را عوض کرد، در خطی، دودویی، و چیزی که مرتب بودن می‌خرد جواب می‌گیرد.

جایی که کار گیر می‌کند، ترجمه شرط از یک زبان دیگر است

بیشتر کسانی که در ایران با پایتون شروع می‌کنند، پیش از آن کمی سی یا جاوااسکریپت دیده‌اند، معمولا در درس‌های دانشگاهی یا در قالب یک سایت. نتیجه‌اش این است که شرط‌ها با آکولاد در ذهن ساخته می‌شوند و بعد به تورفتگی برگردانده می‌شوند، و هر خطای منطقی این صفحه از همان‌جا می‌آید: else ای که یک سطح غلط نشسته، یا بدنه‌ای که چون آکولادی نیست، بی‌صدا یک سطر بیشتر یا کمتر گرفته است. تورفتگی در پایتون نظر نیست، نحو است، و ویرایشگر باید همان اول جوری تنظیم شود که فاصله و تب را قاطی نکند.

ابزار، و سالی که این حرف درست است

در سال ۲۰۲۶ ابزار پیش‌فرض برای همین یک دسته خطا ruff است که هم قالب‌بندی می‌کند و هم قاعده‌ها را بررسی، و جای زوج black و flake8 را گرفته که تا حدود سال ۲۰۲۳ استاندارد بودند. رایگان و متن‌باز است، یک فایل اجرایی تنهاست و پس از نصب به شبکه کاری ندارد. آنچه از آن به این صفحه مربوط است این است که تورفتگی مشکوک و continue بی‌اثر را همان موقع تایپ کردن علامت می‌زند، پیش از آنکه اصلا اجرا کنید.

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

کنار این

بالای این