C#转Python第2.1篇:Python 函数竟然不用写返回类型?我 15 年 C# 习惯崩了

发布时间:2026/7/1 2:34:55
C#转Python第2.1篇:Python 函数竟然不用写返回类型?我 15 年 C# 习惯崩了 在 C# 里写函数就像写一份正式的合同——访问修饰符、返回类型、参数类型一个都不能少。在 Python 里写函数就像发微信消息——def加个名字参数随意类型什么的...看心情。当我第一次写 Python 函数发现不需要声明返回类型的时候我的内心是这代码...能跑结果不仅能跑还跑得飞快。Python 的函数定义就是这么任性。函数定义基础对比C# 版本// 标准写法必须声明返回类型和参数类型 public string Greet(string name) { return $Hello, {name}!; } // 无返回值用 void public void SayHello() { Console.WriteLine(Hello!); } // 静态方法最常见 public static int Add(int a, int b) { return a b; }Python 版本# 标准写法def 加个名字就行 def greet(name): return fHello, {name}! # 无返回值不用写 void def say_hello(): print(Hello!) # Python 没有 static直接定义就行 def add(a, b): return a b对比一下对比项C#Python定义关键字返回类型 方法名()def 函数名():返回类型必须声明不用声明可选注解参数类型必须声明不用声明可选注解无返回值void不用写访问修饰符public/private/protected没有约定 _ 开头为私有静态方法static关键字不需要模块级别就是分号和大括号需要不需要C# 的函数定义像写合同Python 的像发微信——在吗帮我算个数。参数类型大对比默认参数C# 版本// C# 4.0 开始支持默认参数 public string Greet(string name, string greeting Hello) { return ${greeting}, {name}!; } // 调用 Greet(张三); // Hello, 张三! Greet(张三, 你好); // 你好, 张三!Python 版本# Python 一直支持默认参数 def greet(name, greetingHello): return f{greeting}, {name}! # 调用 greet(张三) # Hello, 张三! greet(张三, 你好) # 你好, 张三!Python 的默认参数从诞生那天就有C# 等了 8 个版本才加上。可变参数C# 版本// params 关键字 public int Sum(params int[] numbers) { int total 0; foreach (var n in numbers) total n; return total; } // 调用 Sum(1, 2, 3); // 6 Sum(1, 2, 3, 4, 5); // 15 // C# 没有 **kwargs只能用命名参数或对象Python 版本# *args 接收任意数量的位置参数 def sum_numbers(*args): return sum(args) # 调用 sum_numbers(1, 2, 3) # 6 sum_numbers(1, 2, 3, 4, 5) # 15 # **kwargs 接收任意数量的关键字参数 def print_info(**kwargs): for key, value in kwargs.items(): print(f{key}: {value}) # 调用 print_info(name张三, age25, city北京)C# 有paramsPython 有*args和**kwargs——Python 的更灵活C# 的更明确。参数顺序规则C# 版本// C# 的参数顺序很严格 public void Method(int a, string b default, int c 0) { // 可选参数必须在必需参数后面 } // 调用时必须按顺序或者用命名参数 Method(1); Method(1, hello); Method(1, hello, 10); Method(1, c: 10); // 跳过 b用命名参数Python 版本# Python 的参数顺序更灵活 def method(a, bdefault, c0): pass # 调用时可以用关键字参数跳过前面的 method(1) method(1, hello) method(1, hello, 10) method(1, c10) # 跳过 b用关键字参数C# 用命名参数跳过默认值Python 直接用关键字参数更直观。仅限关键字/位置参数C# 版本// C# 用参数名前加命名关键字语法糖 // 没有真正的仅限关键字或仅限位置参数Python 版本# Python 3.8 支持仅限位置参数 def func(name, /, age25): # name 只能按位置传age 可以用关键字 pass # Python 3 支持仅限关键字参数 def func(name, *, age, city): # age 和 city 只能用关键字传 pass # 调用 func(张三, age25, city北京) func(张三, 25, 北京) # 报错city 只能用关键字Python 有 C# 没有的参数控制能力——/和*分隔位置和关键字参数。函数参数类型完整对比# Python 的参数类型完整示例 def func(a, b, /, c, d, *, e, f, **kwargs): a, b: 仅位置参数只能按位置传递 c, d: 位置或关键字参数可以按位置或关键字传递 e, f: 仅限关键字参数只能按关键字传递 **kwargs: 额外的关键字参数 print(fa{a}, b{b}, c{c}, d{d}, e{e}, f{f}) print(fkwargs{kwargs}) # 调用方式 func(1, 2, 3, 4, e5, f6) # 正确 func(1, 2, c3, d4, e5, f6) # 正确 func(1, 2, 3, 4, 5, 6) # 正确c, d, e, f 都按位置 func(1, 2, 3, 4, e5, f6, g7) # 正确g 进入 kwargs # 以下调用会报错 # func(1, 2, 3, 4, 5, 6, 7) # 错误e, f 只能用关键字 # func(a1, b2, c3, d4) # 错误a, b 只能用位置C# 的参数类型// C# 的参数类型 void Func(int a, int b, int c 0, int d 0) { // a, b: 必需参数 // c, d: 可选参数 } // C# 没有真正的仅限关键字或仅限位置参数 // 但可以用命名参数模拟 void CallExamples() { Func(1, 2); // 正确 Func(1, 2, 3); // 正确 Func(1, 2, c: 3); // 正确命名参数 Func(1, 2, d: 4); // 正确跳过 c // Func(a: 1, b: 2); // 错误a, b 是必需参数必须按位置 }参数类型C#Python必需参数void Func(int a)def func(a):可选参数void Func(int a 0)def func(a0):仅位置参数不支持def func(a, /):仅关键字参数不支持def func(*, a):可变位置参数params int[] argsdef func(*args):可变关键字参数不支持def func(**kwargs):命名参数支持支持Python 的参数控制能力比 C# 强大得多——可以精确控制每个参数是位置传递还是关键字传递。返回值对比C# 版本// 单个返回值 public int Add(int a, int b) { return a b; } // 多个返回值用 out 参数 public void Divide(int a, int b, out int quotient, out int remainder) { quotient a / b; remainder a % b; } // 多个返回值用元组C# 7 public (int Sum, int Product) Calculate(int a, int b) { return (a b, a * b); } // 调用 var result Calculate(3, 4); Console.WriteLine(result.Sum); // 7 Console.WriteLine(result.Product); // 12Python 版本# 单个返回值 def add(a, b): return a b # 多个返回值天然支持元组 def divide(a, b): quotient a // b remainder a % b return quotient, remainder # 返回元组 # 调用 q, r divide(10, 3) # 直接解包 print(q, r) # 3 1 # 多个返回值更灵活 def calculate(a, b): return a b, a * b # 不用括号也行 sum_val, product calculate(3, 4)C# 的多返回值要专门的语法out 参数或元组Python 天生就是多返回值——返回的其实是个元组。函数作为参数C# 版本// 用委托 public int Apply(Funcint, int func, int value) { return func(value); } // 用 lambda int result Apply(x x * 2, 5); // 10 // 定义委托类型 public delegate int Transform(int x); public int ApplyTransform(Transform func, int value) { return func(value); }Python 版本# 函数直接作为参数不需要委托 def apply(func, value): return func(value) # 用 lambda result apply(lambda x: x * 2, 5) # 10 # 用普通函数 def double(x): return x * 2 result apply(double, 5) # 10C# 需要委托或 Func/Action 类型Python 直接传函数名就行——Python 的函数就是一等公民。文档字符串 vs XML 注释C# 版本/// summary /// 计算两个数的和 /// /summary /// param namea第一个数/param /// param nameb第二个数/param /// returns两数之和/returns public int Add(int a, int b) { return a b; }Python 版本def add(a, b): 计算两个数的和 Args: a: 第一个数 b: 第二个数 Returns: 两数之和 return a b # 查看文档 help(add) print(add.__doc__)C# 用 XML 注释Python 用文档字符串——Python 的文档字符串可以直接通过__doc__属性访问。设计哲学C# 的函数定义是显式契约——类型声明就是合同条款编译器帮你检查适合大型项目和团队协作。Python 的函数定义是鸭子契约——只要能用就行类型注解是可选的适合快速开发。C# 的函数定义像是写法律文书每一条都清清楚楚 Python 的函数定义像是发微信消息帮我算个数就够了。坑点提醒默认参数是对象引用——Python 的经典坑# 危险默认参数是可变对象 def append_to(item, lst[]): lst.append(item) return lst print(append_to(1)) # [1] print(append_to(2)) # [1, 2] 不是 [2] # 正确写法 def append_to(item, lstNone): if lst is None: lst [] lst.append(item) return lstC# 的默认参数是编译时常量——不会有这个问题// C# 的默认参数在编译时确定 public void AppendTo(string item, Liststring lst null) { lst ?? new Liststring(); lst.Add(item); }可变参数顺序——*args 和 **kwargs 的位置# 正确顺序普通参数 → *args → keyword-only → **kwargs def func(a, b, *args, keyNone, **kwargs): pass函数名约定——Python 用下划线命名# C# 风格Python 也能用但不符合约定 def GetUserName(): # 不推荐 # Python 风格 def get_user_name(): # 推荐 pass迁移指南C# 开发者最容易犯的错这一章节的内容比较特殊迁移指南会在后续文章中详细讨论。一句话总结C# 的函数定义是先签合同再干活Python 的函数定义是先干活再说。下一篇咱们来聊聊 Lambda 表达式——C# 的x x * 2和 Python 的lambda x: x * 2看似相似但用法大不同。示例代码C# 转 Python 全系列配套练习代码含 48 章示例GitHubhttps://github.com/LadyKiller1025/csharp-python-demosGiteehttps://gitee.com/qakjhzx/csharp-python-demos 欢迎点赞、收藏、转发你的支持是我持续创作的动力