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 f"Hello, {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, greeting="Hello"):
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="张三", age=25, city="北京")
C# 有 params,Python 有 *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, b="default", c=0):
pass
# 调用时可以用关键字参数跳过前面的
method(1)
method(1, "hello")
method(1, "hello", 10)
method(1, c=10) # 跳过 b,用关键字参数
C# 用"命名参数"跳过默认值,Python 直接用关键字参数,更直观。
仅限关键字/位置参数
C# 版本:
// C# 用参数名前加命名关键字(语法糖)
// 没有真正的"仅限关键字"或"仅限位置"参数
Python 版本:
# Python 3.8+ 支持仅限位置参数
def func(name, /, age=25):
# name 只能按位置传,age 可以用关键字
pass
# Python 3 支持仅限关键字参数
def func(name, *, age, city):
# age 和 city 只能用关键字传
pass
# 调用
func("张三", age=25, city="北京")
func("张三", 25, "北京") # 报错:city 只能用关键字
Python 有 C# 没有的参数控制能力——/ 和 * 分隔位置和关键字参数。
函数参数类型完整对比
# Python 的参数类型完整示例
def func(a, b, /, c, d, *, e, f, **kwargs):
"""
a, b: 仅位置参数(只能按位置传递)
c, d: 位置或关键字参数(可以按位置或关键字传递)
e, f: 仅限关键字参数(只能按关键字传递)
**kwargs: 额外的关键字参数
"""
print(f"a={a}, b={b}, c={c}, d={d}, e={e}, f={f}")
print(f"kwargs={kwargs}")
# 调用方式
func(1, 2, 3, 4, e=5, f=6) # 正确
func(1, 2, c=3, d=4, e=5, f=6) # 正确
func(1, 2, 3, 4, 5, 6) # 正确(c, d, e, f 都按位置)
func(1, 2, 3, 4, e=5, f=6, g=7) # 正确(g 进入 kwargs)
# 以下调用会报错
# func(1, 2, 3, 4, 5, 6, 7) # 错误:e, f 只能用关键字
# func(a=1, b=2, c=3, d=4) # 错误: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(a=0): |
| 仅位置参数 | 不支持 | def func(a, /): |
| 仅关键字参数 | 不支持 | def func(*, a): |
| 可变位置参数 | params int[] args |
def 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); // 12
Python 版本:
# 单个返回值
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(Func<int, 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) # 10
C# 需要委托或 Func/Action 类型,Python 直接传函数名就行——Python 的函数就是一等公民。
文档字符串 vs XML 注释
C# 版本:
/// <summary>
/// 计算两个数的和
/// </summary>
/// <param name="a">第一个数</param>
/// <param name="b">第二个数</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, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
C# 的默认参数是编译时常量——不会有这个问题:
// C# 的默认参数在编译时确定
public void AppendTo(string item, List<string> lst = null)
{
lst ??= new List<string>();
lst.Add(item);
}
可变参数顺序——*args 和 **kwargs 的位置:
# 正确顺序:普通参数 → *args → keyword-only → **kwargs
def func(a, b, *args, key=None, **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 章示例)
💬 欢迎点赞、收藏、转发,你的支持是我持续创作的动力!
更多推荐


所有评论(0)