C#转Python第2.3篇:上周帮同事 review 代码,他一行 Python 让我愣了 5 秒
C#转Python第2.3篇:上周帮同事 review 代码,他一行 Python 让我愣了 5 秒
上周帮同事 review 代码,他甩过来一行 Python:[x * 2 for x in nums if x > 0]。我愣了 5 秒——这不就是我用 LINQ 写了三年的 Where().Select() 吗?一行顶三行,Python 玩家果然任性。
不过等我看到后面的需求——分组、聚合、延迟执行——我又默默打开了 C# 的 LINQ。两种写法各有各的杀手锏,C# 的 LINQ 像是"流水线",Python 的推导式像是"压缩包"。
基础语法对比
C# 版本:
var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// 筛选
var evens = numbers.Where(x => x % 2 == 0).ToList();
// 转换
var doubled = numbers.Select(x => x * 2).ToList();
// 排序
var sorted = numbers.OrderByDescending(x => x).ToList();
// 聚合
var sum = numbers.Sum();
var avg = numbers.Average();
// 链式调用
var result = numbers
.Where(x => x > 3)
.Select(x => x * 2)
.OrderBy(x => x)
.ToList();
// C# 12 集合表达式(更简洁)
int[] nums = [1, 2, 3, 4, 5];
List<int> list = [1, 2, 3, 4, 5];
IEnumerable<int> more = [.. nums, 6, 7, 8]; // 展开运算符
Python 版本:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 筛选
evens = [x for x in numbers if x % 2 == 0]
# 转换
doubled = [x * 2 for x in numbers]
# 排序
sorted_list = sorted(numbers, reverse=True)
# 聚合
total = sum(numbers)
avg = sum(numbers) / len(numbers)
# 链式操作
result = [x * 2 for x in numbers if x > 3]
result = sorted([x * 2 for x in numbers if x > 3])
对比一下:
| 操作 | C# LINQ | Python 列表推导式 |
|---|---|---|
| 筛选 | list.Where(x => x > 0) |
[x for x in list if x > 0] |
| 转换 | list.Select(x => x * 2) |
[x * 2 for x in list] |
| 排序 | list.OrderBy(x => x) |
sorted(list) |
| 聚合 | list.Sum() |
sum(list) |
| 链式 | .Where().Select().ToList() |
[... for x in list if ...] |
C# 的 LINQ 是"方法链",Python 的推导式是"表达式压缩"。
复杂操作对比
多条件筛选
C# 版本:
var users = GetUsers();
// 多条件筛选
var result = users
.Where(u => u.Age >= 18)
.Where(u => u.IsActive)
.Where(u => u.Score > 80)
.ToList();
// 或者用 && 连接
var result2 = users
.Where(u => u.Age >= 18 && u.IsActive && u.Score > 80)
.ToList();
Python 版本:
users = get_users()
# 多条件筛选
result = [u for u in users if u["age"] >= 18 and u["is_active"] and u["score"] > 80]
# 或者分行写
result = [
u for u in users
if u["age"] >= 18
and u["is_active"]
and u["score"] > 80
]
嵌套循环
C# 版本:
// 笛卡尔积
var colors = new[] { "红", "蓝", "绿" };
var sizes = new[] { "S", "M", "L" };
var combinations = colors
.SelectMany(c => sizes, (c, s) => new { Color = c, Size = s })
.ToList();
// 或者用嵌套 Select
var combinations2 = colors
.SelectMany(c => sizes.Select(s => new { Color = c, Size = s }))
.ToList();
Python 版本:
# 笛卡尔积
colors = ["红", "蓝", "绿"]
sizes = ["S", "M", "L"]
combinations = [(c, s) for c in colors for s in sizes]
# 等价于
combinations = []
for c in colors:
for s in sizes:
combinations.append((c, s))
Python 的嵌套循环更直观,C# 需要 SelectMany。
字典推导
C# 版本:
var users = new List<User> { /* ... */ };
// 转换为字典
var userDict = users.ToDictionary(u => u.Id, u => u.Name);
// 用 LINQ 生成字典
var priceDict = products
.Where(p => p.IsActive)
.ToDictionary(p => p.Id, p => p.Price);
Python 版本:
users = [{"id": 1, "name": "张三"}, ...]
# 字典推导
user_dict = {u["id"]: u["name"] for u in users}
# 带条件的字典推导
price_dict = {
p["id"]: p["price"]
for p in products
if p["is_active"]
}
集合推导
C# 版本:
var numbers = new List<int> { 1, 2, 2, 3, 3, 3, 4 };
// 用 HashSet 去重
var unique = new HashSet<int>(numbers);
// 用 LINQ Distinct
var distinct = numbers.Distinct().ToList();
Python 版本:
numbers = [1, 2, 2, 3, 3, 3, 4]
# 集合推导(自动去重)
unique = {x for x in numbers} # {1, 2, 3, 4}
# 列表去重(保持顺序)
distinct = list(dict.fromkeys(numbers)) # [1, 2, 3, 4]
性能对比
C# 版本:
// LINQ 延迟执行
var query = numbers.Where(x => x > 0); // 不会立即执行
var result = query.ToList(); // 这里才执行
// 可以利用延迟执行优化
var result = numbers
.Where(x => x > 0) // 延迟
.Select(x => x * 2) // 延迟
.Take(10) // 延迟
.ToList(); // 执行,只处理前 10 个
Python 版本:
# 列表推导式立即执行
result = [x * 2 for x in numbers if x > 0] # 立即创建整个列表
# 生成器表达式延迟执行
result = (x * 2 for x in numbers if x > 0) # 不会立即创建列表
# 用 next() 取第一个
first = next(x * 2 for x in numbers if x > 0)
# 或者用生成器配合函数
result = list(islice(
(x * 2 for x in numbers if x > 0),
10
))
C# 的 LINQ 天然支持延迟执行,Python 需要用生成器表达式。
可读性对比
C# 版本:
// 复杂的链式调用
var result = orders
.Where(o => o.Status == OrderStatus.Completed)
.Where(o => o.OrderDate >= DateTime.Now.AddDays(-30))
.SelectMany(o => o.Items)
.GroupBy(i => i.ProductId)
.Select(g => new
{
ProductId = g.Key,
TotalQuantity = g.Sum(i => i.Quantity),
TotalAmount = g.Sum(i => i.Quantity * i.Price)
})
.OrderByDescending(x => x.TotalAmount)
.Take(10)
.ToList();
Python 版本:
# 等价的 Python 写法
result = [
{
"product_id": product_id,
"total_quantity": sum(i["quantity"] for i in items),
"total_amount": sum(i["quantity"] * i["price"] for i in items)
}
for product_id, items in groupby(
[
i for o in orders
if o["status"] == "completed"
and o["order_date"] >= datetime.now() - timedelta(days=30)
for i in o["items"]
],
key=lambda i: i["product_id"]
)
]
# 或者用 Pandas(更清晰)
import pandas as pd
df = pd.DataFrame(orders)
result = (
df[df["status"] == "completed"]
.query("order_date >= @thirty_days_ago")
.explode("items")
.groupby("product_id")
.agg({"quantity": "sum", "amount": "sum"})
.nlargest(10, "amount")
)
C# 的 LINQ 链更清晰,Python 的复杂推导式可读性较差。
设计哲学
C# 的 LINQ 是"方法链模式"——每个操作返回新的序列,可以链式调用,适合复杂的数据处理管道。
Python 的推导式是"表达式压缩"——用一行代码表达复杂的逻辑,适合简单的转换和筛选。
C# 的 LINQ 像是"流水线",每个环节清晰可见; Python 的推导式像是"压缩包",解压后才能看清内部。
坑点提醒
Python 推导式的变量泄漏——变量会泄漏到外部作用域:
x = 10
result = [x for x in range(5)]
print(x) # 4!不是 10 了
# 避免方法:Python 3.0+ 的推导式有自己的作用域
# 但在旧版本中,推导式变量会泄漏
过度嵌套的推导式——可读性灾难:
# 不好:嵌套太深
result = [
f(x, y)
for x in range(10)
for y in range(10)
if g(x, y)
for f in [h1, h2, h3]
if condition(f, x, y)
]
# 好:拆分成多步
filtered = [(x, y) for x in range(10) for y in range(10) if g(x, y)]
result = [f(x, y) for x, y in filtered for f in [h1, h2, h3] if condition(f, x, y)]
C# 的 LINQ 方法命名——英语不好会很痛苦:
// 需要记住很多方法名
// Where, Select, SelectMany, OrderBy, ThenBy
// GroupBy, Distinct, Except, Intersect, Union
// Any, All, First, Last, Single
// Sum, Average, Min, Max, Count
// Python 的关键字更直观
# for, in, if, sorted, sum, len
性能陷阱——不必要的转换:
// 不好:多次转换
var result = list.Where(x => x > 0).Select(x => x * 2).ToList();
// 好:一次转换
var result = list.Where(x => x > 0).Select(x => x * 2).ToList();
// 上面两个一样,但注意不要在循环中多次调用 ToList()
# 不好:多次创建列表
result1 = [x for x in numbers if x > 0]
result2 = [x * 2 for x in result1]
# 好:一次完成
result = [x * 2 for x in numbers if x > 0]
迁移指南:C# 开发者最容易犯的错
-
混淆推导式和生成器表达式:
[x for x in list]立即创建列表,(x for x in list)是生成器 -
忘记推导式变量泄漏:Python 3.12 之前,推导式变量会泄漏到外部作用域
-
过度使用推导式:复杂逻辑应该用普通循环,可读性更重要
-
**用
sorted()代替.OrderBy()**:sorted()返回新列表,原列表不变 -
**用
sum()/len()代替.Average()**:Python 没有内置的average()函数 -
**用
in代替.Contains()**:"x" in list比list.__contains__("x")更 Pythonic
一句话总结
C# 的 LINQ 是"流水线",Python 的推导式是"压缩包"——都能处理集合,但风格完全不同。
下一篇咱们来聊聊生成器与迭代器——C# 的 yield return 和 Python 的 yield,几乎一样的设计哲学!
📦 示例代码:C# 转 Python 全系列配套练习代码(含 48 章示例)
💬 欢迎点赞、收藏、转发,你的支持是我持续创作的动力!
更多推荐


所有评论(0)