上周面试,面试官冷不丁问了一句:"Python 的 lambda 和 C# 的 Lambda 有什么区别?"我脱口而出:"都是匿名函数嘛,差不多。"面试官笑了笑:"那你给我分别写一个接受任意数量参数的版本?"
那一刻我才意识到——C# 的 Lambda 和 Python 的 lambda 虽然长得像,骨子里完全不是一回事。C# 的 Lambda 是"全能选手",Python 的 lambda 是"临时工"。
基础语法对比
C# 版本:
// Lambda 表达式Func<int, int> square = x => x * x;Func<int, int, int> add = (a, b) => a + b;Action<string> print = msg => Console.WriteLine(msg);// 带代码块的 LambdaFunc<int, int, int> divide = (a, b) =>{if (b == 0)thrownew DivideByZeroException();return a / b;};
Python 版本:
# Lambda 表达式(只能是一行)square = lambda x: x * xadd = lambda a, b: a + bprint_msg = lambda msg: print(msg)# Python 的 lambda 只能是单个表达式# 不能写多行代码块# divide = lambda a, b: if b == 0: ... # 语法错误!
对比一下:
| | |
|---|
| x => x * 2 | lambda x: x * 2 |
| | |
| | |
| | |
| | |
C# 的 Lambda 是"完整版",Python 的是"精简版"。
用法场景对比
作为参数传递
C# 版本:
// 在 LINQ 中使用var numbers = new List<int> { 1, 2, 3, 4, 5 };// Lambda 作为参数var doubled = numbers.Select(x => x * 2).ToList();var evens = numbers.Where(x => x % 2 == 0).ToList();var sum = numbers.Aggregate(0, (acc, x) => acc + x);// 自定义方法接受 Lambdapublic List<T> Filter<T>(List<T> list, Func<T, bool> predicate){return list.Where(predicate).ToList();}var result = Filter(numbers, x => x > 3);
Python 版本:
# 在内置函数中使用numbers = [1, 2, 3, 4, 5]# Lambda 作为参数doubled = list(map(lambda x: x * 2, numbers))evens = list(filter(lambda x: x % 2 == 0, numbers))sum_result = reduce(lambda acc, x: acc + x, numbers)# 自定义函数接受 Lambdadeffilter_list(lst, predicate):return [x for x in lst if predicate(x)]result = filter_list(numbers, lambda x: x > 3)
C# 的 Lambda 配合 LINQ 使用,Python 的配合 map/filter 使用。
作为返回值
C# 版本:
// 返回 Lambdapublic Func<int, int> Multiplier(int factor){return x => x * factor;}var triple = Multiplier(3);Console.WriteLine(triple(5)); // 15// 多行 Lambda 作为返回值public Func<int, int, int> CreateCalculator(string operation){return (a, b) => operation switch {"add" => a + b,"sub" => a - b,"mul" => a * b, _ => thrownew ArgumentException() };}
Python 版本:
# 返回 Lambdadefmultiplier(factor):returnlambda x: x * factortriple = multiplier(3)print(triple(5)) # 15# Python 的 lambda 只能是单表达式# 不能写多行逻辑,所以复杂场景要用普通函数defcreate_calculator(operation):if operation == "add":returnlambda a, b: a + belif operation == "sub":returnlambda a, b: a - belif operation == "mul":returnlambda a, b: a * belse:raise ValueError(f"Unknown operation: {operation}")
C# 的 Lambda 可以包含复杂逻辑,Python 的只能是简单表达式。
Lambda 对比普通函数
C# 版本:
// Lambda vs 普通方法Func<int, int, int> addLambda = (a, b) => a + b;intAddMethod(int a, int b){return a + b;}// Lambda 可以访问外部变量(闭包)int multiplier = 10;Func<int, int> multiply = x => x * multiplier;
Python 版本:
# Lambda vs 普通函数add_lambda = lambda a, b: a + bdefadd_function(a, b):return a + b# Lambda 也可以访问外部变量(闭包)multiplier = 10multiply = lambda x: x * multiplier
Python 的 lambda 就是普通函数的语法糖,C# 的 Lambda 有独立的语法地位。
常见用法模式
排序
C# 版本:
// 按属性排序var users = new List<User> { /* ... */ };users.Sort((a, b) => a.Name.CompareTo(b.Name));users = users.OrderBy(u => u.Age).ToList();users = users.OrderByDescending(u => u.Salary).ToList();
Python 版本:
# 按属性排序users = [{"name": "张三", "age": 25}, /* ... */]users.sort(key=lambda u: u["name"])users.sort(key=lambda u: u["age"])users.sort(key=lambda u: u["salary"], reverse=True)
字典转换
C# 版本:
// 用 Lambda 做转换var dict = new Dictionary<string, int> { ["a"] = 1, ["b"] = 2 };var values = dict.Select(kv => kv.Value).ToList();var newDict = dict.ToDictionary(kv => kv.Key, kv => kv.Value * 2);
Python 版本:
# 用 Lambda 做转换dict_data = {"a": 1, "b": 2}values = list(map(lambda x: x[1], dict_data.items()))new_dict = {k: v * 2for k, v in dict_data.items()}
设计哲学
C# 的 Lambda 是"完整的匿名函数"——支持多行代码、闭包、泛型推断,是 LINQ 的核心。
Python 的 lambda 是"轻量级语法糖"——只能写单个表达式,复杂逻辑还是用普通函数。
C# 的 Lambda 像是"迷你函数",能干的事和普通函数差不多; Python 的 lambda 像是"一次性纸杯",用完就扔,别指望它能干重活。
坑点提醒
Python 的 lambda 只能是表达式——不能包含语句:
# 错误!lambda 不能包含语句# func = lambda x: print(x) if x > 0 else None # 语法错误# 正确写法:用三元表达式func = lambda x: print(x) if x > 0elseNone# 这是表达式,可以# 或者直接用普通函数deffunc(x):if x > 0: print(x)
C# 的 Lambda 会捕获变量引用——循环中的常见坑:
// 错误!所有 Lambda 捕获的是同一个变量var actions = new List<Action>();for (int i = 0; i < 5; i++){ actions.Add(() => Console.WriteLine(i));}// 执行所有 action,输出都是 5!// 正确写法:创建局部变量var actions = new List<Action>();for (int i = 0; i < 5; i++){int temp = i; actions.Add(() => Console.WriteLine(temp));}// 输出 0, 1, 2, 3, 4
Python 的 lambda 同样捕获引用——同样的坑:
# 错误!funcs = []for i in range(5): funcs.append(lambda: print(i))for f in funcs: f() # 都输出 4!# 正确写法:用默认参数创建新作用域funcs = []for i in range(5): funcs.append(lambda i=i: print(i))for f in funcs: f() # 输出 0, 1, 2, 3, 4
不要滥用 Lambda——保持可读性:
# 不好:过度使用 lambdadata = list(map(lambda x: x * 2, filter(lambda x: x > 0, numbers)))# 好:用列表推导式data = [x * 2for x in numbers if x > 0]
迁移指南:C# 开发者最容易犯的错
这一章节的内容比较特殊,迁移指南会在后续文章中详细讨论。
一句话总结
C# 的 Lambda 是"全能匿名函数",Python 的 lambda 是"一次性纸杯"——好用但别指望它能干重活。
下一篇咱们来聊聊列表推导式 vs LINQ——两种语言处理集合的"语法糖"大比拼。