在 C# 里写 for 循环,你得这样:
for (int i = 0; i < 10; i++) { Console.WriteLine(i); }在 Python 里?这样:
for i in range(10): print(i)发现了没?Python 的 for 循环没有i++,没有i < 10,只有一个range(10)。
还有那个让 C# 程序员崩溃的for...else——循环没被 break 就执行 else?这是什么鬼?
今天咱们来聊聊循环结构——C# 的"传统 for" vs Python 的"for-in"。
for 循环
C# 版本:
// 传统 for 循环 for (int i = 0; i < 10; i++) { Console.WriteLine(i); } // foreach 循环 int[] numbers = { 1, 2, 3, 4, 5 }; foreach (var num in numbers) { Console.WriteLine(num); } // 倒序遍历 for (int i = numbers.Length - 1; i >= 0; i--) { Console.WriteLine(numbers[i]); } // 带索引的 foreach for (int i = 0; i < numbers.Length; i++) { Console.WriteLine($"{i}: {numbers[i]}"); }Python 版本:
# for-in 循环(Python 只有这一种 for) for i in range(10): print(i) # 遍历列表 numbers = [1, 2, 3, 4, 5] for num in numbers: print(num) # 倒序遍历 for num in reversed(numbers): print(num) # 带索引的遍历 for i, num in enumerate(numbers): print(f"{i}: {num}")| 对比项 | C# | Python |
|---|---|---|
| 传统 for | for (int i=0; i<10; i++) | for i in range(10): |
| foreach | foreach (var x in list) | for x in list: |
| 倒序 | for (int i=len-1; i>=0; i--) | for x in reversed(list): |
| 带索引 | 手动维护i | enumerate(list) |
| 步长 | i += 2 | range(0, 10, 2) |
Python 的 for 循环是"for-in"风格——你只需要说"遍历这个",不需要告诉它怎么走。C# 的传统 for 循环是"命令式"的,你得告诉它从哪开始、到哪结束、每次加多少。
while 循环
C# 版本:
int i = 0; while (i < 10) { Console.WriteLine(i); i++; } // do-while 循环(Python 没有) int j = 0; do { Console.WriteLine(j); j++; } while (j < 10);Python 版本:
i = 0 while i < 10: print(i) i += 1 # Python 没有 do-while,但可以模拟 # 方法 1:while True + break while True: print(i) i += 1 if i >= 10: break # 方法 2:使用 walrus 运算符(3.8+) while (i := i + 1) <= 10: print(i)C# 有 do-while,Python 没有。Python 的替代方案是while True + break,或者用 walrus 运算符:=。
循环控制
C# 版本:
for (int i = 0; i < 100; i++) { if (i == 5) continue; // 跳过 5 if (i == 10) break; // 遇到 10 停止 Console.WriteLine(i); }Python 版本:
for i in range(100): if i == 5: continue # 跳过 5 if i == 10: break # 遇到 10 停止 print(i)break和continue的用法在两种语言里几乎一样——这是少数几个完全相同的地方。
for-else:Python 独有的"反直觉"设计
这是 Python 最让人困惑的特性之一:
# for-else 在循环正常结束时执行(没有 break) for i in range(10): if i == 5: print("找到了 5") break else: # 循环正常结束(没有 break)才执行 print("没找到 5") # 实际应用场景:搜索 def find_item(lst, target): for item in lst: if item == target: return item else: # 循环正常结束,没有 return return NoneC# 没有 for-else,Python 的 for-else 在循环没有被 break 时执行 else 块。这个设计很反直觉,但用对了场景会很方便。
enumerate 和 zip
C# 的索引遍历:
string[] names = { "Alice", "Bob", "Charlie" }; for (int i = 0; i < names.Length; i++) { Console.WriteLine($"{i + 1}. {names[i]}"); } // 并行遍历 string[] names2 = { "Alice", "Bob" }; int[] ages = { 25, 30 }; for (int i = 0; i < names2.Length; i++) { Console.WriteLine($"{names2[i]}: {ages[i]}"); }Python 的 enumerate 和 zip:
# enumerate(自动索引) names = ["Alice", "Bob", "Charlie"] for i, name in enumerate(names, start=1): print(f"{i}. {name}") # zip(并行遍历) names2 = ["Alice", "Bob"] ages = [25, 30] for name, age in zip(names2, ages): print(f"{name}: {age}") # enumerate + zip students = ["Alice", "Bob"] scores = [90, 85] for i, (name, score) in enumerate(zip(students, scores)): print(f"{i + 1}. {name}: {score}")Python 的enumerate()和zip()让你告别手动索引的痛苦。C# 得手动维护i,Python 直接解包就行。
推导式预告
Python 的列表推导式(第二阶段详细讲):
numbers = [1, 2, 3, 4, 5] # 传统 for 循环 squares = [] for x in numbers: squares.append(x ** 2) # 列表推导式 squares = [x ** 2 for x in numbers] # [1, 4, 9, 16, 25] # 带条件的推导式 even_squares = [x ** 2 for x in numbers if x % 2 == 0] # [4, 16] # 字典推导式 square_dict = {x: x ** 2 for x in numbers} # {1: 1, 2: 4, ...} # 集合推导式 square_set = {x ** 2 for x in numbers} # {1, 4, 9, 16, 25}列表推导式是 Python 的杀手锏——一行代码顶 C# 的Select().ToList()。
设计哲学
C# 的哲学是多种循环——for、foreach、while、do-while,传统风格,类型安全,LINQ 扩展。
Python 的哲学是统一风格——for x in iterable是唯一写法,迭代器协议让任何可迭代对象都能用 for,enumerate 和 zip 告别手动索引。
C# 的 for 循环是"命令式"的,你得告诉它怎么走; Python 的 for 循环是"声明式"的,你只需要说"遍历这个"。
更深层的原因:
C# 的 for 循环需要明确的起始、终止、步长,这是C 风格的延续
Python 的 for 循环只需要一个可迭代对象,这是迭代器协议的体现
真实场景:在处理文件行时,Python 的 for 循环非常优雅:
# 逐行读取文件 with open("data.txt") as f: for line in f: # 直接遍历文件对象 print(line.strip())C# 得这样写:
// 逐行读取文件 foreach (var line in File.ReadLines("data.txt")) { Console.WriteLine(line); }Python 的for line in f直接遍历文件对象,C# 需要File.ReadLines()方法。
迁移指南:C# 开发者最容易犯的错
忘记 range 是左闭右开:
range(5)是 0-4,不是 0-5以为 for-else 很奇怪:它是用来搜索的,找到就 break,没找到就执行 else
忘记 enumerate:Python 不需要手动维护索引
以为 zip 会以最长为准:zip 以最短为准,用
zip_longest以最长为准遍历时修改列表:Python 不允许,用推导式或遍历副本
推荐工具:用 VS Code + Python 插件,它会帮你检查循环的常见错误。
坑点提醒
range 的边界——range 是左闭右开的:
for i in range(5): # 0, 1, 2, 3, 4(不包括 5) print(i) for i in range(1, 5): # 1, 2, 3, 4 print(i)for-else 的执行条件——循环没有 break 才执行 else:
for i in range(10): if i == 5: break else: print("循环没有 break") # 这不会执行(因为 break 了)修改列表的陷阱——遍历时不能安全修改列表:
lst = [1, 2, 3, 4, 5] # 正确做法:遍历副本或使用推导式 lst = [x for x in lst if x % 2 != 0]zip 的长度——zip 以最短的为准:
a = [1, 2, 3] b = ['a', 'b'] print(list(zip(a, b))) # [(1, 'a'), (2, 'b')] # 如果要以最长为准,用 itertools.zip_longest from itertools import zip_longest print(list(zip_longest(a, b, fillvalue=None)))一句话总结
Python 的
for...else是个"反直觉"的设计——循环没被 break 就执行 else。
下一篇咱们来聊聊列表和数组——C# 的Array和List在 Python 里合体了,还有那个让 C# 程序员眼红的列表推导式。
获取更多资源
📦代码仓库:
GitHub:https://github.com/LadyKiller1025/csharp-python-demos
Gitee:https://gitee.com/qakjhzx/csharp-python-demos
💬 欢迎点赞、收藏、转发,你的支持是我持续创作的动力!