一文詳解Python的流程控制if/for/while
本文覆蓋:條件語句(if/elif/else + 三元)、循環(huán)語句(for/while + else 子句)、range/enumerate/zip 并行迭代、break/continue/pass 循環(huán)控制、match-case 模式匹配(3.10+)、常見陷阱與最佳實踐,最后用兩個實操 Demo 收尾。
1. 介紹:為什么需要流程控制
1.1 一句話理解
流程控制 = 程序的「大腦決策系統(tǒng)」。沒有流程控制的程序就是一條直線——從第一行執(zhí)行到最后一行,中間不做任何判斷、不重復任何步驟?,F(xiàn)實中哪有這么簡單的活兒?
1.2 三大基本結(jié)構(gòu)
所有編程語言的流程控制都圍繞這三個結(jié)構(gòu)展開:
| 結(jié)構(gòu) | 作用 | Python 關(guān)鍵字 |
|---|---|---|
| 順序結(jié)構(gòu) | 代碼從上到下依次執(zhí)行 | (默認行為) |
| 選擇結(jié)構(gòu) | 根據(jù)條件決定走哪條路 | if / elif / else / match-case |
| 循環(huán)結(jié)構(gòu) | 重復執(zhí)行某段代碼 | for / while |
1.3 Python 的特殊之處
跟 C/Java 比,Python 的流程控制有幾個顯著區(qū)別:
# 1. 沒有大括號 {},靠縮進劃分代碼塊
if True:
print("縮進就是命")
print("縮進錯了就 SyntaxError")
# 2. 循環(huán)可以帶 else 子句(是的你沒看錯,循環(huán)也有 else)
for i in range(3):
print(i)
else:
print("循環(huán)正常結(jié)束(沒被 break)")
# 3. 條件表達式不用括號包裹(當然加了也不報錯)
if x > 0: # ?
if (x > 0): # ? 但多余
2. 條件語句:if / elif / else 與三元表達式
2.1 原理:Python 的真值測試
Python 的條件判斷不是「判斷 True/False」,而是真值測試(truthiness testing)。任何對象都能被 if 測試,Python 會調(diào)用內(nèi)置的 bool() 函數(shù)來決定走哪條路。
# bool() 的底層邏輯(偽代碼)
def bool(obj):
# 1. 先找 __bool__ 方法
if hasattr(obj, '__bool__'):
return obj.__bool__()
# 2. 再找 __len__ 方法
if hasattr(obj, '__len__'):
return obj.__len__() > 0
# 3. 都沒有?默認 True
return True
假值(Falsy)清單
以下對象在 if 中等價于 False:
| 類型 | 假值 | 說明 |
|---|---|---|
NoneType | None | 空對象 |
bool | False | 布爾假 |
int | 0, 0 | 整數(shù)零 |
float | 0.0 | 浮點零 |
complex | 0j | 復數(shù)零 |
str | "" | 空字符串 |
list / tuple | [], () | 空序列 |
dict / set | {}, set() | 空映射/集合 |
range | range(0) | 空范圍 |
# 驗證假值
for val in [None, False, 0, 0.0, "", [], {}, set(), range(0)]:
print(f"{repr(val):>10} -> {'假值' if not val else '真值'}")
# 輸出:
# None -> 假值
# False -> 假值
# 0 -> 假值
# 0.0 -> 假值
# '' -> 假值
# [] -> 假值
# {} -> 假值
# set() -> 假值
# range(0, 0) -> 假值
踩坑點: 0.0 是假值,但 0.0000001 不是。別用浮點數(shù)做條件判斷,精度問題會咬人。
2.2 if / elif / else 完整語法
# 完整結(jié)構(gòu)
if condition_1:
# 條件1為真時執(zhí)行
pass
elif condition_2:
# 條件1為假、條件2為真時執(zhí)行
pass
elif condition_3:
# 前面都假、條件3為真時執(zhí)行
pass
else:
# 以上條件全假時執(zhí)行(可選)
pass
執(zhí)行流程
condition_1 ──True──? 執(zhí)行代碼塊1 ──? 跳出整個if
│
False
▼
condition_2 ──True──? 執(zhí)行代碼塊2 ──? 跳出整個if
│
False
▼
condition_3 ──True──? 執(zhí)行代碼塊3 ──? 跳出整個if
│
False
▼
else(可選)──? 執(zhí)行else代碼塊
實際示例:成績等級判定
def grade_level(score: float) -> str:
"""根據(jù)分數(shù)返回等級"""
if score >= 90:
return "A - 優(yōu)秀"
elif score >= 80:
return "B - 良好"
elif score >= 70:
return "C - 中等"
elif score >= 60:
return "D - 及格"
else:
return "F - 不及格"
# 測試
for score in [95, 85, 75, 65, 55]:
print(f"{score}分 -> {grade_level(score)}")
# 輸出:
# 95分 -> A - 優(yōu)秀
# 85分 -> B - 良好
# 75分 -> C - 中等
# 65分 -> D - 及格
# 55分 -> F - 不及格
C++ 對比: Python 沒有 switch 語句(3.10 前沒有,3.10 后用 match-case 替代)。多個 elif 就是 Python 式的 switch。在 C++ 里你可以 switch(score / 10),Python 里通常用 elif 鏈或者查表法(bisect 模塊)。
2.3 三元表達式(條件表達式)
當 if-else 只有一個表達式時,Python 提供了簡潔的三元寫法:
# 語法:value_if_true if condition else value_if_false
result = "成年" if age >= 18 else "未成年"
# 等價于
if age >= 18:
result = "成年"
else:
result = "未成年"
嵌套三元(謹慎使用)
# 三層嵌套三元 —— 能用但別濫用
status = "優(yōu)秀" if score >= 90 else ("及格" if score >= 60 else "不及格")
# 更推薦拆開寫
if score >= 90:
status = "優(yōu)秀"
elif score >= 60:
status = "及格"
else:
status = "不及格"
踩坑點: 三元表達式的求值順序是先判斷條件,再求值對應分支,不是兩個分支都求值。
# 安全:只有條件為真時才調(diào)用 expensive_func() result = cheap_value if condition else expensive_func()
2.4 條件組合:and / or / not
# and:兩邊都真才真(短路:左邊假就不看右邊了)
if age >= 18 and has_id:
print("可以進入")
# or:一邊真就真(短路:左邊真就不看右邊了)
if is_vip or is_admin:
print("有特權(quán)")
# not:取反
if not is_banned:
print("賬號正常")
短路求值的妙用
# 模式1:默認值賦值(Python 3.8+ 用海象運算符更優(yōu)雅)
name = user_input or "匿名"
# 模式2:安全調(diào)用(避免 None 上的屬性訪問)
# 如果 obj 不為 None,才調(diào)用 obj.method()
obj is not None and obj.method()
# 模式3:鏈式比較(Python 獨有,C++ 不行)
if 0 <= score <= 100:
print("合法分數(shù)")
# 等價于
if 0 <= score and score <= 100:
print("合法分數(shù)")
C++ 對比: C++ 里 0 <= score <= 100 會被解析成 (0 <= score) <= 100,即先算 0 <= score 得到 true/false(1/0),再拿這個值跟 100 比——永遠為真!Python 的鏈式比較是語法糖,會正確展開成 0 <= score and score <= 100。
3. 循環(huán)語句:for / while 與 else 子句
3.1 for 循環(huán):遍歷的藝術(shù)
Python 的 for 不是 C 的 for(i=0; i<n; i++),它是基于迭代器協(xié)議的——每次從可迭代對象里取一個元素,直到取完。
# 基本語法
for element in iterable:
# 對每個 element 執(zhí)行
pass
# 遍歷列表
fruits = ["蘋果", "香蕉", "橙子"]
for fruit in fruits:
print(fruit)
# 遍歷字符串
for char in "Hello":
print(char, end=" ") # H e l l o
# 遍歷字典
person = {"name": "yance", "age": 30, "role": "blogger"}
for key in person: # 默認遍歷 key
print(key, person[key])
for key, value in person.items(): # 同時取 key 和 value
print(f"{key}: {value}")
迭代器協(xié)議底層原理
# for 循環(huán)的等價偽代碼
iterator = iter(iterable) # 調(diào)用 iterable.__iter__()
while True:
try:
element = next(iterator) # 調(diào)用 iterator.__next__()
# 執(zhí)行循環(huán)體
...
except StopIteration: # 迭代器耗盡
break
# 手動模擬 for 循環(huán) my_list = [10, 20, 30] it = iter(my_list) print(type(it)) # <class 'list_iterator'> print(next(it)) # 10 print(next(it)) # 20 print(next(it)) # 30 # print(next(it)) # StopIteration!
3.2 while 循環(huán):條件驅(qū)動
# 基本語法
while condition:
# condition 為真時反復執(zhí)行
pass
# 倒計時
count = 5
while count > 0:
print(f"倒計時:{count}")
count -= 1
print("發(fā)射!??")
# 輸出:
# 倒計時:5
# 倒計時:4
# 倒計時:3
# 倒計時:2
# 倒計時:1
# 發(fā)射!??
while True + break 模式
# 經(jīng)典模式:無限循環(huán) + 條件退出
while True:
user_input = input("輸入 quit 退出:")
if user_input == "quit":
break
print(f"你輸入了:{user_input}")
踩坑點: while 循環(huán)最容易犯的錯就是忘記更新條件變量,導致死循環(huán)。
# ? 死循環(huán)!count 永遠是 5
count = 5
while count > 0:
print(count)
# 忘了 count -= 1
# ? 正確
count = 5
while count > 0:
print(count)
count -= 1
3.3 循環(huán)的 else 子句(Python 獨有特性)
這是 Python 最反直覺的特性之一——循環(huán)也有 else。
語義
for...else:循環(huán)正常結(jié)束(沒被break打斷)時,執(zhí)行else塊while...else:條件變假導致循環(huán)結(jié)束時(沒被break打斷),執(zhí)行else塊
# for...else:查找質(zhì)數(shù)
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(f"{n} = {x} * {n // x}")
break
else:
# 如果內(nèi)層 for 沒被 break(即沒找到因子),說明 n 是質(zhì)數(shù)
print(f"{n} 是質(zhì)數(shù)")
# 輸出:
# 2 是質(zhì)數(shù)
# 3 是質(zhì)數(shù)
# 4 = 2 * 2
# 5 是質(zhì)數(shù)
# 6 = 2 * 3
# 7 是質(zhì)數(shù)
# 8 = 2 * 4
# 9 = 3 * 3
理解 else 的觸發(fā)條件
# 情況1:正常結(jié)束 -> else 執(zhí)行
for i in range(3):
print(i)
else:
print("else 執(zhí)行了") # ? 會執(zhí)行
# 情況2:被 break -> else 不執(zhí)行
for i in range(3):
print(i)
if i == 1:
break
else:
print("else 執(zhí)行了") # ? 不會執(zhí)行
循環(huán)執(zhí)行流程:
for/while ──? 循環(huán)體
│
┌───────┴───────┐
│ │
遇到 break 正常結(jié)束
│ │
▼ ▼
跳出循環(huán) 執(zhí)行 else 塊
(跳過 else) 然后繼續(xù)后續(xù)代碼
踩坑點: 很多人把 for...else 理解成「循環(huán)沒執(zhí)行時才走 else」,這是錯的??昭h(huán)也會走 else:
for i in range(0): # 循環(huán)體一次都不執(zhí)行
pass
else:
print("else 照樣執(zhí)行") # ? 會執(zhí)行,因為沒有 break
最佳實踐: 如果你覺得 for...else 難讀,用標志變量替代完全沒問題:
found = False
for x in range(2, n):
if n % x == 0:
found = True
break
if not found:
print(f"{n} 是質(zhì)數(shù)")
4. range / enumerate / zip 并行迭代
4.1 range:生成整數(shù)序列
range 是 Python 中最常用的迭代工具之一,它不實際生成列表,而是一個惰性序列對象。
# 三種形式
range(stop) # 0, 1, 2, ..., stop-1
range(start, stop) # start, start+1, ..., stop-1
range(start, stop, step) # start, start+step, start+2*step, ...
# 基本用法
for i in range(5):
print(i, end=" ") # 0 1 2 3 4
for i in range(2, 6):
print(i, end=" ") # 2 3 4 5
for i in range(0, 10, 2):
print(i, end=" ") # 0 2 4 6 8
# 倒序
for i in range(10, 0, -1):
print(i, end=" ") # 10 9 8 7 6 5 4 3 2 1
range 的惰性特性
r = range(1000000) # 不會占內(nèi)存! print(type(r)) # <class 'range'> print(len(r)) # 1000000 print(r[0]) # 0 —— 支持索引 print(r[-1]) # 999999 print(500 in r) # True —— 支持成員測試 # range 對象只存儲 start, stop, step 三個值 # 不管范圍多大,內(nèi)存占用恒定 import sys print(sys.getsizeof(range(10))) # 48 字節(jié) print(sys.getsizeof(range(1000000))) # 48 字節(jié) —— 一樣大!
踩坑點: range 對象不支持 + 拼接和 * 重復,這些是 list 的操作。
# ? TypeError range(3) + range(3) # ? 轉(zhuǎn)成 list 或用 itertools.chain list(range(3)) + list(range(3)) # [0, 1, 2, 0, 1, 2]
4.2 enumerate:帶索引遍歷
當你需要「同時拿索引和元素」時,enumerate 是 Pythonic 的做法。
# ? 不推薦:手動維護索引
i = 0
for fruit in fruits:
print(i, fruit)
i += 1
# ? 不推薦:用 range(len())
for i in range(len(fruits)):
print(i, fruits[i])
# ? 推薦:enumerate
for index, fruit in enumerate(fruits):
print(index, fruit)
# enumerate 還能指定起始索引
for index, fruit in enumerate(fruits, start=1):
print(f"第{index}個:{fruit}")
enumerate 底層實現(xiàn)
# enumerate 的等價實現(xiàn)
def my_enumerate(iterable, start=0):
n = start
for elem in iterable:
yield n, elem
n += 1
# 它返回的是 enumerate 對象,不是列表
e = enumerate(["a", "b", "c"])
print(type(e)) # <class 'enumerate'>
print(list(e)) # [(0, 'a'), (1, 'b'), (2, 'c')]
4.3 zip:并行迭代多個序列
zip 把多個可迭代對象「拉鏈式」合并,每次取各序列的一個元素組成元組。
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
cities = ["北京", "上海", "深圳"]
# 基本用法:兩兩配對
for name, age in zip(names, ages):
print(f"{name} 今年 {age} 歲")
# 多個序列并行
for name, age, city in zip(names, ages, cities):
print(f"{name}, {age}歲, 住在{city}")
# 輸出:
# Alice, 25歲, 住在北京
# Bob, 30歲, 住在上海
# Charlie, 35歲, 住在深圳
zip 的「木桶效應」
# zip 以最短的那個序列為準 a = [1, 2, 3, 4, 5] b = ["a", "b", "c"] print(list(zip(a, b))) # [(1, 'a'), (2, 'b'), (3, 'c')] —— 4和5丟了! # 如果要保留所有元素,用 itertools.zip_longest from itertools import zip_longest print(list(zip_longest(a, b, fillvalue="?"))) # [(1, 'a'), (2, 'b'), (3, 'c'), (4, '?'), (5, '?')]
zip 的妙用:矩陣轉(zhuǎn)置
# 經(jīng)典技巧:二維矩陣轉(zhuǎn)置
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
transposed = list(zip(*matrix))
print(transposed) # [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
# *matrix 展開 = zip([1,2,3], [4,5,6], [7,8,9])
# zip 從每個子列表取第1個元素組成第1個元組,以此類推
zip 創(chuàng)建字典
keys = ["name", "age", "city"]
values = ["yance", 30, "深圳"]
# Pythonic 的字典構(gòu)造法
person = dict(zip(keys, values))
print(person) # {'name': 'yance', 'age': 30, 'city': '深圳'}
Python 3 的坑: Python 3 的 zip 返回的是迭代器(惰性的),只能遍歷一次。Python 2 返回的是列表。
z = zip([1, 2], ["a", "b"]) print(list(z)) # [(1, 'a'), (2, 'b')] print(list(z)) # [] —— 迭代器已經(jīng)耗盡了!
5. break / continue / pass 與循環(huán)控制
5.1 三者對比
| 關(guān)鍵字 | 作用 | 影響范圍 |
|---|---|---|
break | 跳出當前循環(huán)(徹底結(jié)束循環(huán)) | 最近的 for / while |
continue | 跳過本次迭代剩余代碼,進入下一次 | 最近的 for / while |
pass | 什么都不做(占位符) | 無影響 |
5.2 break:跳出循環(huán)
# 找到第一個能被7整除的數(shù)
for n in range(1, 100):
if n % 7 == 0:
print(f"找到了:{n}")
break # 找到就停,不繼續(xù)了
# 輸出:找到了:7
break 只跳一層
# 嵌套循環(huán)中,break 只跳出最內(nèi)層
for i in range(3):
for j in range(3):
if j == 1:
break # 只跳出內(nèi)層 for
print(f"i={i}, j={j}")
# 輸出:
# i=0, j=0
# i=1, j=0
# i=2, j=0
跳出多層循環(huán)的技巧
# 方法1:標志變量
found = False
for i in range(5):
for j in range(5):
if i * j == 6:
found = True
break # 跳出內(nèi)層
if found:
break # 跳出外層
# 方法2:for...else + break(更 Pythonic)
for i in range(5):
for j in range(5):
if i * j == 6:
print(f"找到:i={i}, j={j}")
break
else:
continue # 內(nèi)層沒 break,繼續(xù)外層
break # 內(nèi)層 break 了,也跳出外層
# 方法3:封裝成函數(shù) + return(最推薦)
def find_pair():
for i in range(5):
for j in range(5):
if i * j == 6:
return i, j
return None
result = find_pair()
5.3 continue:跳過本次
# 打印所有奇數(shù)
for n in range(1, 10):
if n % 2 == 0:
continue # 偶數(shù)跳過,不執(zhí)行后面的 print
print(n, end=" ") # 1 3 5 7 9
# 過濾列表中的空字符串
data = ["hello", "", "world", None, "python", ""]
for item in data:
if not item: # 空字符串和 None 都是假值
continue
print(item)
# 輸出:
# hello
# world
# python
踩坑點: continue 在 while 循環(huán)中要特別小心——確保它在條件變量更新之前不會跳過更新。
# ? 死循環(huán)!continue 跳過了 count += 1
count = 0
while count < 5:
if count == 2:
continue # count 永遠停在 2...
print(count)
count += 1
# ? 正確:把更新放在 continue 之前
count = 0
while count < 5:
if count != 2:
print(count)
count += 1 # 更新一定執(zhí)行
5.4 pass:占位符
pass 是一個空操作——什么都不做。它存在的唯一意義是語法占位,因為 Python 的代碼塊不能為空。
# 1. 空函數(shù)/類的占位
def not_implemented_yet():
pass # 先占個位,以后再寫
class EmptyClass:
pass
# 2. 條件分支的占位
if debug_mode:
pass # TODO: 加調(diào)試邏輯
else:
do_something()
# 3. 在 try-except 中忽略異常
try:
risky_operation()
except SomeError:
pass # 故意忽略這個異常
pass vs … (Ellipsis)
# Python 3 中,... 也能做占位符
def stub():
...
class Empty:
...
# ... 和 pass 效果一樣,但 ... 是一個真正的對象(Ellipsis)
# pass 是語句,... 是表達式
# 類型標注中 ... 有特殊含義
def callback() -> ...:
...
最佳實踐: except: pass 是 Python 中最被詬病的模式之一(被稱為「吞掉異?!梗?。如果你真的要忽略異常,至少記錄一下日志:
# ? 吞異常,出了問題無從排查
try:
do_something()
except Exception:
pass
# ? 至少記錄一下
import logging
try:
do_something()
except Exception as e:
logging.warning(f"操作失敗: {e}")
6. match-case 模式匹配(Python 3.10+)
6.1 介紹
Python 3.10 引入了 match-case,這不是簡單的 switch-case,而是結(jié)構(gòu)化模式匹配(Structural Pattern Matching)——源自函數(shù)式語言(如 Haskell、Scala、Rust)的強大特性。
# 基本語法
match subject:
case pattern_1:
# 匹配 pattern_1 時執(zhí)行
pass
case pattern_2:
# 匹配 pattern_2 時執(zhí)行
pass
case _:
# 都不匹配時執(zhí)行(_ 是通配符)
pass
6.2 各種模式
字面量模式
def http_status(code: int) -> str:
match code:
case 200:
return "OK"
case 404:
return "Not Found"
case 500:
return "Internal Server Error"
case _:
return "Unknown"
print(http_status(200)) # OK
print(http_status(404)) # Not Found
變量綁定模式
# 匹配的值會綁定到變量上
point = (3, 4)
match point:
case (0, 0):
print("原點")
case (0, y):
print(f"在Y軸上,y={y}") # y 綁定為 4
case (x, 0):
print(f"在X軸上,x={x}")
case (x, y):
print(f"坐標:({x}, {y})") # x=3, y=4
類模式
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def describe(point: Point) -> str:
match point:
case Point(x=0, y=0):
return "原點"
case Point(x=0, y=y):
return f"Y軸上,y={y}"
case Point(x=x, y=0):
return f"X軸上,x={x}"
case Point(x=x, y=y):
return f"普通點({x}, {y})"
print(describe(Point(3, 4))) # 普通點(3, 4)
序列模式
def process_command(cmd: list) -> str:
match cmd:
case ["quit"]:
return "退出程序"
case ["help"]:
return "顯示幫助"
case ["go", direction]:
return f"向{direction}移動"
case ["go", direction, distance]:
return f"向{direction}移動{distance}步"
case ["look", *rest]:
return f"查看:{rest}" # *rest 捕獲剩余元素
case _:
return "未知命令"
print(process_command(["go", "north"])) # 向north移動
print(process_command(["go", "north", 5])) # 向north移動5步
print(process_command(["look", "around"])) # 查看:['around']
映射(字典)模式
def handle_event(event: dict) -> str:
match event:
case {"type": "click", "x": x, "y": y}:
return f"點擊坐標({x}, {y})"
case {"type": "keypress", "key": key}:
return f"按鍵:{key}"
case {"type": "scroll", "delta": delta}:
return f"滾動:{delta}"
case _:
return "未知事件"
print(handle_event({"type": "click", "x": 100, "y": 200}))
# 點擊坐標(100, 200)
守衛(wèi)(Guard)模式
def classify_number(n: int) -> str:
match n:
case n if n < 0:
return "負數(shù)"
case n if n == 0:
return "零"
case n if n < 10:
return "小正數(shù)"
case n if n < 100:
return "中等正數(shù)"
case _:
return "大正數(shù)"
print(classify_number(-5)) # 負數(shù)
print(classify_number(0)) # 零
print(classify_number(7)) # 小正數(shù)
print(classify_number(50)) # 中等正數(shù)
print(classify_number(999)) # 大正數(shù)
or 模式
def day_type(day: str) -> str:
match day.lower():
case "saturday" | "sunday":
return "周末"
case "monday" | "tuesday" | "wednesday" | "thursday" | "friday":
return "工作日"
case _:
return "無效輸入"
6.3 match-case vs if-elif-else 對比
# 傳統(tǒng) if-elif 寫法
def handle_http(method, path):
if method == "GET" and path == "/users":
return "獲取用戶列表"
elif method == "GET" and path.startswith("/users/"):
user_id = path.split("/")[-1]
return f"獲取用戶{user_id}"
elif method == "POST" and path == "/users":
return "創(chuàng)建用戶"
else:
return "未知路由"
# match-case 寫法(更清晰)
def handle_http_v2(method, path):
parts = path.strip("/").split("/")
match (method, parts):
case ("GET", ["users"]):
return "獲取用戶列表"
case ("GET", ["users", user_id]):
return f"獲取用戶{user_id}"
case ("POST", ["users"]):
return "創(chuàng)建用戶"
case _:
return "未知路由"
踩坑點: match-case 中的變量名如果和已有變量重名,會被當作新的綁定模式,而不是值比較!
status = 200
# ? 這不是比較 status == 200
match response:
case status: # 這是變量綁定!永遠匹配
print(f"綁定了: {status}") # status 被重新賦值為 response 的值
# ? 要做值比較,用字面量或加了點號的變量
match response:
case 200:
print("OK")
case _: # 通配符
print("其他")
7. 常見陷阱與最佳實踐
7.1 陷阱清單
陷阱1:在循環(huán)中修改正在遍歷的列表
# ? 邊遍歷邊刪除,會跳過元素
nums = [1, 2, 2, 3, 4, 4, 5]
for n in nums:
if n % 2 == 0:
nums.remove(n)
print(nums) # [1, 2, 3, 4, 5] —— 沒刪干凈!
# ? 方法1:遍歷副本
for n in nums[:]: # nums[:] 創(chuàng)建副本
if n % 2 == 0:
nums.remove(n)
# ? 方法2:列表推導式(更 Pythonic)
nums = [n for n in nums if n % 2 != 0]
# ? 方法3:filter
nums = list(filter(lambda n: n % 2 != 0, nums))
陷阱2:可變默認參數(shù)與循環(huán)
# ? 默認參數(shù)在函數(shù)定義時只創(chuàng)建一次
def add_item(item, lst=[]): # lst 在多次調(diào)用間共享!
lst.append(item)
return lst
print(add_item(1)) # [1]
print(add_item(2)) # [1, 2] —— 不是 [2]!
# ? 用 None 做默認值
def add_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
陷阱3:浮點數(shù)做循環(huán)條件
# ? 浮點精度問題可能導致意外行為
i = 0.0
while i != 1.0: # 可能永遠不等!
i += 0.1
print(i)
if i > 2: # 加個安全閥
break
# ? 用整數(shù)范圍 + 縮放
for i in range(11):
val = i / 10.0
print(val)
陷阱4:無限循環(huán)耗盡資源
# ? 忘記更新條件
while True:
response = fetch_data()
if response is None:
break
process(response)
# 如果 fetch_data 永遠不返回 None...死循環(huán)
# ? 加超時/最大重試限制
max_retries = 100
retry_count = 0
while retry_count < max_retries:
response = fetch_data()
if response is None:
break
process(response)
retry_count += 1
7.2 最佳實踐
實踐1:用列表推導式替代簡單循環(huán)
# ? 傳統(tǒng)寫法
squares = []
for i in range(10):
squares.append(i ** 2)
# ? 列表推導式
squares = [i ** 2 for i in range(10)]
# 帶條件過濾
even_squares = [i ** 2 for i in range(10) if i % 2 == 0]
實踐2:用 any() / all() 替代顯式循環(huán)
# ? 顯式循環(huán)找滿足條件的元素
def has_negative(nums):
for n in nums:
if n < 0:
return True
return False
# ? any() 一行搞定
def has_negative(nums):
return any(n < 0 for n in nums)
# all():所有元素都滿足條件
all_positive = all(n > 0 for n in nums)
實踐3:循環(huán)中避免重復計算
# ? 每次循環(huán)都調(diào)用 len()
for i in range(len(data)):
process(data[i], len(data)) # len(data) 每次都算
# ? 緩存長度
n = len(data)
for i in range(n):
process(data[i], n)
實踐4:用字典替代冗長的 if-elif 鏈
# ? 冗長的 if-elif
def calculate(a, b, op):
if op == "+":
return a + b
elif op == "-":
return a - b
elif op == "*":
return a * b
elif op == "/":
return a / b
else:
raise ValueError(f"未知運算符: {op}")
# ? 字典分發(fā)(策略模式)
import operator
ops = {
"+": operator.add,
"-": operator.sub,
"*": operator.mul,
"/": operator.truediv,
}
def calculate(a, b, op):
if op not in ops:
raise ValueError(f"未知運算符: {op}")
return ops[op](a, b)
8. 實操 Demo
8.1 猜數(shù)字游戲
"""
猜數(shù)字游戲
- 電腦隨機生成 1-100 的數(shù)字
- 玩家輸入猜測,電腦提示「大了」或「小了」
- 限制最多 7 次機會(二分法理論最優(yōu))
- 支持「放棄」提前退出
"""
import random
def guess_number_game() -> None:
target = random.randint(1, 100)
max_attempts = 7
print("=" * 40)
print("?? 猜數(shù)字游戲(1-100)")
print(f"你有 {max_attempts} 次機會,輸入 'quit' 放棄")
print("=" * 40)
for attempt in range(1, max_attempts + 1):
user_input = input(f"第 {attempt}/{max_attempts} 次猜測:").strip()
# 處理退出
if user_input.lower() in ("quit", "exit", "q"):
print(f"你放棄了!答案是 {target}")
return
# 處理非數(shù)字輸入
if not user_input.isdigit():
print("?? 請輸入數(shù)字!")
continue # 不消耗次數(shù)(視規(guī)則而定)
guess = int(user_input)
# 范圍檢查
if not (1 <= guess <= 100):
print("?? 請輸入 1-100 之間的數(shù)字!")
continue
# 比較
if guess == target:
print(f"?? 恭喜!{attempt} 次猜中!")
return
elif guess < target:
print("?? 小了!")
else:
print("?? 大了!")
# 循環(huán)正常結(jié)束(次數(shù)用完沒猜中)
else:
print(f"?? 機會用完!答案是 {target}")
# 運行游戲
if __name__ == "__main__":
guess_number_game()
運行效果:
======================================== ?? 猜數(shù)字游戲(1-100) 你有 7 次機會,輸入 'quit' 放棄 ======================================== 第 1/7 次猜測:50 ?? 小了! 第 2/7 次猜測:75 ?? 大了! 第 3/7 次猜測:62 ?? 小了! 第 4/7 次猜測:68 ?? 大了! 第 5/7 次猜測:65 ?? 恭喜!5 次猜中!
8.2 簡易計算器
"""
簡易計算器
- 支持加減乘除、取余、冪運算
- 支持連續(xù)計算
- 輸入 'quit' 退出
- 完整的錯誤處理
"""
import operator
import sys
# 運算符映射表
OPERATIONS = {
"+": (operator.add, "加法"),
"-": (operator.sub, "減法"),
"*": (operator.mul, "乘法"),
"/": (operator.truediv, "除法"),
"http://": (operator.floordiv, "整除"),
"%": (operator.mod, "取余"),
"**": (operator.pow, "冪運算"),
}
def get_number(prompt: str) -> float | None:
"""安全地獲取數(shù)字輸入,返回 None 表示退出"""
while True:
raw = input(prompt).strip()
if raw.lower() in ("quit", "exit", "q"):
return None
try:
return float(raw)
except ValueError:
print("?? 輸入無效,請重新輸入數(shù)字!")
def get_operator() -> str | None:
"""獲取運算符輸入"""
ops_display = " / ".join(OPERATIONS.keys())
while True:
raw = input(f"選擇運算符 ({ops_display}):").strip()
if raw.lower() in ("quit", "exit", "q"):
return None
if raw in OPERATIONS:
return raw
print("?? 無效運算符,請重新輸入!")
def calculate(a: float, op: str, b: float) -> float:
"""執(zhí)行計算"""
func, _ = OPERATIONS[op]
return func(a, b)
def calculator() -> None:
print("=" * 50)
print("?? 簡易計算器")
print("輸入 'quit' 隨時退出")
print("=" * 50)
while True:
# 獲取第一個操作數(shù)
a = get_number("請輸入第一個數(shù):")
if a is None:
break
# 獲取運算符
op = get_operator()
if op is None:
break
# 獲取第二個操作數(shù)
b = get_number("請輸入第二個數(shù):")
if b is None:
break
# 執(zhí)行計算(帶異常處理)
try:
result = calculate(a, op, b)
op_name = OPERATIONS[op][1]
print(f"\n? 結(jié)果:{a} {op} = {result}\n")
# 特殊情況提示
if op == "/" and b == 0:
print("(除以零會產(chǎn)生 inf)")
elif op == "http://" and b == 0:
print("(整除零會拋異常,已被捕獲)")
except ZeroDivisionError:
print("\n? 錯誤:除數(shù)不能為零!\n")
except OverflowError:
print("\n? 錯誤:結(jié)果溢出!\n")
except Exception as e:
print(f"\n? 未知錯誤:{e}\n")
print("感謝使用,再見!??")
# 運行計算器
if __name__ == "__main__":
calculator()
運行效果:
================================================== ?? 簡易計算器 輸入 'quit' 隨時退出 ================================================== 請輸入第一個數(shù):10 選擇運算符 (+ / - / * / / / // / % / **):** 請輸入第二個數(shù):3 ? 結(jié)果:10.0 ** 3.0 = 1000.0 請輸入第一個數(shù):100 選擇運算符 (+ / - / * / / / // / % / **):/ 請輸入第二個數(shù):0 ? 錯誤:除數(shù)不能為零! 請輸入第一個數(shù):quit 感謝使用,再見!??
9. 總結(jié)
9.1 知識圖譜
流程控制
├── 條件分支
│ ├── if / elif / else # 基本條件判斷
│ ├── 三元表達式 # value if cond else value
│ ├── and / or / not # 邏輯組合 + 短路求值
│ └── match-case (3.10+) # 結(jié)構(gòu)化模式匹配
├── 循環(huán)
│ ├── for # 遍歷可迭代對象
│ ├── while # 條件驅(qū)動循環(huán)
│ └── else 子句 # 循環(huán)正常結(jié)束時執(zhí)行
├── 迭代工具
│ ├── range # 惰性整數(shù)序列
│ ├── enumerate # 帶索引遍歷
│ └── zip # 并行迭代
├── 循環(huán)控制
│ ├── break # 跳出循環(huán)
│ ├── continue # 跳過本次
│ └── pass # 空操作占位
└── 最佳實踐
├── 列表推導式替代簡單循環(huán)
├── any() / all() 替代顯式查找
├── 字典分發(fā)替代 if-elif 鏈
└── 避免在循環(huán)中修改遍歷對象
9.2 速查表
| 場景 | 推薦 | 示例 |
|---|---|---|
| 簡單二選一 | 三元表達式 | x if cond else y |
| 多分支 | if-elif-else | 成績等級判定 |
| 遍歷序列 | for | for item in list |
| 不知道次數(shù) | while | 讀取直到 EOF |
| 帶索引遍歷 | enumerate | for i, v in enumerate(lst) |
| 多序列并行 | zip | for a, b in zip(l1, l2) |
| 復雜結(jié)構(gòu)匹配 | match-case | 解析命令/事件 |
| 查找元素 | any() | any(x > 0 for x in lst) |
| 過濾+變換 | 列表推導式 | [f(x) for x in lst if cond] |
9.3 C++ 程序員的 Python 流程控制速記
| C++ | Python | 備注 |
|---|---|---|
if (x) {} | if x: | 不用括號,靠縮進 |
switch-case | match-case (3.10+) 或 elif 鏈 | 3.10 前沒有 switch |
for (int i=0; i<n; i++) | for i in range(n): | 基于迭代器 |
for (auto& x : container) | for x in container: | 天然支持 |
while (x) | while x: | 一樣 |
break / continue | break / continue | 一樣 |
{} 空代碼塊 | pass | Python 代碼塊不能為空 |
#define MAX 100 | MAX = 100 | 不用預處理器 |
goto | ? 不存在 | 用函數(shù) + return 替代 |
以上就是一文詳解Python的流程控制if/for/while的詳細內(nèi)容,更多關(guān)于Python流程控制if/for/while的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python接口自動化之淺析requests模塊post請求
這篇文章Python接口自動化之淺析requests模塊post請求,以下主要介紹requests模塊中的post請求的使用,post源碼,data、json參數(shù)應用場景及實戰(zhàn)2021-08-08
VSCode設置類似Pycharm控制臺運行Python顯示中間變量的步驟
這篇文章主要介紹了如何在VSCode中設置調(diào)試功能,以實現(xiàn)類似于Pycharm在控制臺輸出中間變量的功能,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2025-03-03
Python參數(shù)傳遞中雙星號(**)和單星號(*)是作用
雙星號(**)和單星號(*)在參數(shù)傳遞中扮演著關(guān)鍵角色,本文主要介紹了Python參數(shù)傳遞中雙星號(**)和單星號(*)是作用,具有一定的參考價值,感興趣的可以了解一下2024-05-05
python 劃分數(shù)據(jù)集為訓練集和測試集的方法
今天小編就為大家分享一篇python 劃分數(shù)據(jù)集為訓練集和測試集的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-12-12

