回文章列表
Python11 分鐘閱讀2026年7月28日

Python 縮排跳出 IndentationError?從一週營業額報表搞懂 if / for / while

#Python#if#for#while#迴圈#新手

文章目錄

寫一支程式要處理店裡一週的營業額,才打沒幾行就跳出:

IndentationError: unexpected indent

或是漏看一個冒號,跳出 SyntaxError: expected ':'。這兩個錯誤幾乎是每個 Python 新手都會遇到的第一關——不是邏輯錯了,是連 Python 都還沒開始判斷你的邏輯,就先卡在「格式不對」。

這篇不講抽象語法規則,直接用一份真實情境貫穿到底:一家店一週七天的營業額,sales = [12500, 9800, 15200, 8700, 11300, 20100, 18400]。老闆想知道每天有沒有達標、平日跟假日有什麼不同、什麼時候要提醒補貨——這些問題剛好把 if / elif / else、for、while 全部用上一遍。

用比較運算子回答「有沒有超過」:if / elif / else

先看今天的營業額有沒有達標。Python 比較兩個值用的符號:

運算子意思
==等於
!=不等於
> / <大於/小於
>= / <=大於等於/小於等於

留意 == 是「比較是否相等」,跟等一下會講到的 =(賦值)是完全不同的兩件事。

sales = [12500, 9800, 15200, 8700, 11300, 20100, 18400]
today_sales = sales[0]

if today_sales >= 15000:
    print("達標")
elif today_sales >= 10000:
    print("普通")
else:
    print("低於預期")
普通

today_sales 是 12500,兩萬不到一萬五也到不了,所以第一個 if 條件不成立,Python 接著看 elif——12500 大於等於 10000,條件成立,印出「普通」,後面的 else 直接跳過不看。

這是 if / elif / else 的核心規則:由上往下逐一檢查,第一個成立的區塊執行完就結束,其餘全部跳過。就算後面還有條件也符合,也不會再執行——三選一,永遠只走一條路。elif 可以寫很多個,else 則是「以上皆非」時的最後防線,可以不寫。

and / or / not:把兩個條件兜在一起

只看營業額不夠,老闆還想知道「是不是假日達標」——這需要同時檢查兩個條件,就要用到邏輯運算子:and(兩個都要成立)、or(其中一個成立就算)、not(把結果反過來)。

sales = [12500, 9800, 15200, 8700, 11300, 20100, 18400]
days = ["一", "二", "三", "四", "五", "六", "日"]

for i in range(7):
    is_weekend = days[i] == "六" or days[i] == "日"
    if sales[i] >= 15000 and is_weekend:
        print(f"週{days[i]}:假日且達標,營業額 {sales[i]} 元")
    elif sales[i] >= 15000 and not is_weekend:
        print(f"週{days[i]}:平日達標,營業額 {sales[i]} 元")
週三:平日達標,營業額 15200 元
週六:假日且達標,營業額 20100 元
週日:假日且達標,營業額 18400 元

is_weekend = days[i] == "六" or days[i] == "日" 這行要注意:or 兩邊各自是一個完整的比較(days[i] == "六"、days[i] == "日"),不是把 "六" 跟 "日" 硬湊在一起——這是新手很常寫錯的地方,or 連接的是兩個條件式,不是兩個值。

and 兩邊都要成立才算數,所以「假日且達標」要 sales[i] >= 15000 and is_weekend 同時滿足;not is_weekend 則是把布林值反過來,is_weekend 是 False 時 not is_weekend 就是 True,代表「不是假日」也就是平日。

縮排不是排版習慣,是語法本身

上面的程式碼裡,if 底下那一行 print(...) 前面有 4 個空白,這不是為了好看——Python 靠縮排來判斷一段程式碼屬不屬於這個區塊,別的語言用 { } 做的事,Python 全部交給縮排。少縮或多縮,程式直接跑不起來。

冒號後面忘記換行縮排:

today_sales = 15200
if today_sales >= 15000:
print("達標")
  File "t12.py", line 3
print("達標")
    ^^^^^
IndentationError: expected an indented block after 'if' statement on line 2

縮排量跟前一行對不上(例如混用不同數量的空白):

today_sales = 15200
if today_sales >= 15000:
    print("達標")
     print("恭喜")
  File "t11.py", line 4
     print("恭喜")
IndentationError: unexpected indent

第二個例子裡 print("恭喜") 前面多了一個空白,跟同一個區塊裡其他行的縮排量不一致,Python 完全沒辦法判斷這行到底屬於哪一層,直接報錯。實務上這種問題最常發生在「一部分用 Tab、一部分用空白鍵縮排」——肉眼看起來對齊,但 Python 認的是實際字元。編輯器(VSCode、PyCharm)都能設定「Tab 自動轉空白」,設定好之後這類問題基本不會再發生。記住一個原則:同一支程式從頭到尾都用 4 個空白縮排,不要跟 Tab 混用。

for 迴圈:走訪一份清單,逐筆處理

走訪 list:一次看一天的資料

不想一天一天手動查 sales[0]、sales[1],for 迴圈可以直接走訪整個清單,每一輪拿到一個值:

sales = [12500, 9800, 15200, 8700, 11300, 20100, 18400]
for amount in sales:
    print(f"{amount} 元")
12500 元
9800 元
15200 元
8700 元
11300 元
20100 元
18400 元

for amount in sales 的意思是「從 sales 裡一個一個拿出來,每次都叫它 amount」,跑完整個清單迴圈自然結束,不需要自己數有幾筆。

走訪 range():只要數字、不需要清單裡的值

如果只是要重複做某件事固定次數(例如列印天數編號),不一定要有清單,range() 可以直接產生一串數字:

sales = [12500, 9800, 15200, 8700, 11300, 20100, 18400]
days = ["一", "二", "三", "四", "五", "六", "日"]

total = 0
for i in range(len(sales)):
    total += sales[i]
    print(f"週{days[i]}:{sales[i]} 元")

print(f"本週總營業額:{total} 元")
print(f"平均每天:{total / len(sales):.1f} 元")
週一:12500 元
週二:9800 元
週三:15200 元
週四:8700 元
週五:11300 元
週六:20100 元
週日:18400 元
本週總營業額:96000 元
平均每天:13714.3 元

這裡用 range(len(sales)) 產生索引 i(0 到 6),好處是同一個 i 可以同時拿 sales[i] 跟 days[i],把兩份清單對應起來——比起前面單純 for amount in sales,只要需要「同時用到索引」或「同時走訪兩份清單」,就該用 range(len(...)) 這個寫法。

range(start, stop, step) 的 stop 不包含在內

range() 有一個新手幾乎都踩過的坑:range(start, stop) 產生的數字不含 stop 本身。

for day_num in range(1, 7):
    print(f"第 {day_num} 天")
第 1 天
第 2 天
第 3 天
第 4 天
第 5 天
第 6 天

一週明明有 7 天,range(1, 7) 卻只印到第 6 天——因為 stop 寫的是 7,但 7 這個數字本身不會被包含進去,range(1, 7) 實際產生的是 1、2、3、4、5、6。要印滿 7 天,stop 要多寫一個:

for day_num in range(1, 8):
    print(f"第 {day_num} 天")
第 1 天
第 2 天
第 3 天
第 4 天
第 5 天
第 6 天
第 7 天

記法很單純:想要涵蓋到數字 N,stop 就要寫 N + 1。這也是為什麼前面 range(len(sales)) 能剛好對到索引 0~6——len(sales) 是 7,range(7) 產生 0 到 6,正好是清單的合法索引範圍,一個都不多、一個都不少。

while 迴圈:不知道要跑幾次的時候用

for 適合「清單有幾筆就跑幾次」這種次數固定或事先知道的情境。但如果次數要「跑到某個條件成立才停」,事先根本不知道要跑幾輪,這時候該用 while。

假設老闆想知道:從週一開始累計營業額,要到第幾天才會突破 5 萬元?這個天數要邊算邊看才知道,不適合寫死一個 range():

sales = [12500, 9800, 15200, 8700, 11300, 20100, 18400]

total = 0
day = 0
target = 50000

while total < target:
    total += sales[day]
    day += 1
    print(f"累計到第 {day} 天:{total} 元")

print(f"第 {day} 天營業額累計達到 {total} 元,超過目標 {target} 元")
累計到第 1 天:12500 元
累計到第 2 天:22300 元
累計到第 3 天:37500 元
累計到第 4 天:46200 元
累計到第 5 天:57500 元
第 5 天營業額累計達到 57500 元,超過目標 50000 元

while total < target: 這行是重點——只要條件 total < target 還成立,迴圈就繼續跑;一旦 total 累計到 57500、不再小於 50000,條件變成 False,迴圈自動停止。整個過程不需要事先知道會跑幾輪,這正是 while 存在的意義。

無窮迴圈是怎麼發生的

while 的條件如果永遠不會變成 False,迴圈就會一直跑下去,這叫無窮迴圈。最常見的成因是忘記在迴圈裡更新那個會被拿來判斷條件的變數:

count = 0
while count < 5:
    print(f"提醒第 {count + 1} 次:記得關店前對帳")
    # 忘了寫 count += 1

這支程式不要真的執行——因為 count 從頭到尾都是 0,count < 5 永遠成立,程式會不斷印同一行,直到你按 Ctrl + C 強制中斷為止。修法很直覺,把更新變數的那一行補回去:

count = 0
while count < 5:
    print(f"提醒第 {count + 1} 次:記得關店前對帳")
    count += 1

print("提醒完畢")
提醒第 1 次:記得關店前對帳
提醒第 2 次:記得關店前對帳
提醒第 3 次:記得關店前對帳
提醒第 4 次:記得關店前對帳
提醒第 5 次:記得關店前對帳
提醒完畢

寫 while 迴圈時養成一個習慣:寫完條件之後,回頭確認迴圈裡有沒有一行程式碼會讓這個條件往「結束」的方向前進(像這裡的 count += 1)。找不到那一行,通常就是無窮迴圈的前兆。

break 與 continue:提早結束 vs 跳過這次

break 和 continue 都是用來改變迴圈原本的執行順序,但作用完全不同——break 是「不跑了,直接離開整個迴圈」,continue 是「這一輪不做了,但迴圈繼續跑下一輪」。

先看 break:找出今年第一天營業額破 18000 的日子,一找到就沒必要再往下看了:

sales = [12500, 9800, 15200, 8700, 11300, 20100, 18400]
days = ["一", "二", "三", "四", "五", "六", "日"]

for i in range(len(sales)):
    if sales[i] >= 18000:
        print(f"找到了!週{days[i]} 營業額 {sales[i]} 元,第一天就破 18000")
        break
    print(f"週{days[i]} 還沒破 18000,繼續看下一天")
週一 還沒破 18000,繼續看下一天
週二 還沒破 18000,繼續看下一天
週三 還沒破 18000,繼續看下一天
週四 還沒破 18000,繼續看下一天
週五 還沒破 18000,繼續看下一天
找到了!週六 營業額 20100 元,第一天就破 18000

跑到週六觸發 break,迴圈立刻結束,後面的週日完全沒被檢查——就算週日的營業額也超過 18000,也不會被印出來,因為迴圈已經不存在了。

再看 continue:資料裡混進一筆異常值(例如系統打錯記成負數),要跳過這筆不列入加總,但後面的資料還是要繼續算:

sales = [12500, 9800, -500, 8700, 11300, 20100, 18400]
days = ["一", "二", "三", "四", "五", "六", "日"]

total = 0
for i in range(len(sales)):
    if sales[i] < 0:
        print(f"週{days[i]} 資料異常({sales[i]} 元),跳過不計入")
        continue
    total += sales[i]

print(f"扣除異常資料後,總營業額:{total} 元")
週三 資料異常(-500 元),跳過不計入
扣除異常資料後,總營業額:80800 元

週三觸發 continue,那一輪剩下的 total += sales[i] 被跳過不執行,但迴圈本身沒有停,直接跳到週四繼續跑。這就是 break 跟 continue 最直接的差別:break 之後迴圈不存在了,continue 之後迴圈還在,只是跳過這一輪剩下的部分。

三個新手最常踩的錯誤

= 跟 == 搞混

= 是賦值(把值存進變數),== 是比較(問「這兩個是不是相等」)。if 的條件要用 ==,寫成 = 會直接語法錯誤:

today_sales = 15200
if today_sales = 15000:
    print("剛好一萬五")
  File "t10.py", line 2
    if today_sales = 15000:
       ^^^^^^^^^^^^^^^^^^^
SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?

新版 Python 的錯誤訊息其實已經直接提示「你是不是想打 ==」,看到這個錯誤,第一件事就是檢查 if 那一行是不是把等號少打了一個。

忘記寫冒號

if、elif、else、for、while 這些開啟區塊的關鍵字,那一行結尾一定要有冒號 :,這是告訴 Python「接下來要開始一個縮排區塊了」:

today_sales = 15200
if today_sales >= 15000
    print("達標")
  File "t9.py", line 2
    if today_sales >= 15000
                           ^
SyntaxError: expected ':'

錯誤訊息會直接告訴你少了 :,通常就是漏看那一行的結尾,補上就好。

縮排不一致

前面「縮排」那一節已經示範過 IndentationError 長什麼樣子,這裡再強調一次原因:同一個區塊裡的每一行,縮排的空白數量要完全一樣。混用 Tab 跟空白鍵、或是複製貼上程式碼時帶進了不同數量的空白,都會踩到這個錯誤。編輯器裡把縮排字元設成「顯示空白符號」,肉眼就能看出哪裡對不齊。

小結

這篇把一份七天的營業額清單,從頭到尾用 if / elif / else 判斷達標與否、用 for 走訪清單與 range()、用 while 處理「不知道要跑幾次」的累計問題、再用 break / continue 微調迴圈的執行順序。三個常見錯誤——= 打成 ==、忘記冒號、縮排不一致——幾乎每個新手都會遇到至少一次,看懂錯誤訊息在講什麼,比死背語法規則更有用。

把這些觀念兜在一起做成一個完整的小遊戲,可以練得更扎實:猜數字遊戲那篇從最陽春的版本一路加功能,把 while 跟 if / elif / else 用得更靈活,很適合當作這篇的下一步練習。

相關課程

Python 基礎入門

從零開始學習 Python 程式語言,掌握變數、流程控制、函式與模組化設計,建立扎實的程式設計基礎。

查看課程內容