C#转Python第1.7篇:for 循环的前世今生:C# 的 foreach 在 Python 里变成了什么?
在 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 None
C# 没有 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# 程序员眼红的列表推导式。
📦 代码仓库:
💬 欢迎点赞、收藏、转发,你的支持是我持续创作的动力!
更多推荐

所有评论(0)