C#转Python第1.6篇:if-else 这件事,Python 把选择权交给了缩进
在 C# 里写条件判断,你得这样:
if (x > 0)
{
Console.WriteLine("正数");
}
else if (x < 0)
{
Console.WriteLine("负数");
}
else
{
Console.WriteLine("零");
}
在 Python 里?这样:
if x > 0:
print("正数")
elif x < 0:
print("负数")
else:
print("零")
发现了没?Python 的 elif 比 C# 的 else if 少打一个空格。这就是 Python 的"懒人哲学"。
今天咱们来聊聊条件判断——C# 的"大括号" vs Python 的"缩进"。
基本 if-else
C# 版本:
int x = 5;
if (x > 0)
{
Console.WriteLine("正数");
}
if (x > 0)
{
Console.WriteLine("正数");
}
else
{
Console.WriteLine("非正数");
}
if (x > 0)
{
Console.WriteLine("正数");
}
else if (x < 0)
{
Console.WriteLine("负数");
}
else
{
Console.WriteLine("零");
}
Python 版本:
x = 5
if x > 0:
print("正数")
if x > 0:
print("正数")
else:
print("非正数")
if x > 0:
print("正数")
elif x < 0:
print("负数")
else:
print("零")
| 对比项 | C# | Python |
|---|---|---|
| if | if (condition) { } |
if condition: |
| else | else { } |
else: |
| else if | else if |
elif(Python 独有) |
| 代码块 | {} |
缩进(4 空格) |
| 条件括号 | 必须 | 可选 |
Python 的 elif 是一个关键字,不是两个——else if 变成了 elif,少打一个空格,这就是 Python 的"懒人哲学"。
三元表达式
C# 版本:
int x = 5;
string result = x > 0 ? "正数" : "非正数";
// C# 9+ 模式匹配
string result2 = x switch
{
> 0 => "正数",
< 0 => "负数",
_ => "零"
};
Python 版本:
x = 5
result = "正数" if x > 0 else "非正数"
# Python 3.10+ match-case
match x:
case _ if x > 0:
result2 = "正数"
case _ if x < 0:
result2 = "负数"
case _:
result2 = "零"
# 海象运算符(3.8+)
if (n := len([1, 2, 3])) > 2:
print(f"长度是 {n}")
C# 的三元表达式是 条件 ? 值1 : 值2,Python 的是 值1 if 条件 else 值2——顺序反过来了。
真值判断
这是 C# 程序员最容易踩的坑。
C# 版本:
string s = "hello";
int n = 0;
List<int> list = new List<int>();
if (s != null) { } // 检查 null
if (s.Length > 0) { } // 检查空字符串
if (n != 0) { } // 检查非零
if (list.Count > 0) { } // 检查非空列表
Python 版本:
s = "hello"
n = 0
lst = [1, 2, 3]
empty_list = []
none_val = None
if s: # 非空字符串为 True
print("s 不为空")
if n: # 0 为 False
print("n 不为零")
if lst: # 非空列表为 True
print("lst 不为空")
if empty_list: # 空列表为 False
print("这不会执行")
if none_val: # None 为 False
print("这也不会执行")
# Python 的真值表
# False: None, False, 0, 0.0, "", [], {}, set(), tuple()
# True: 其他所有值
| 特性 | C# | Python |
|---|---|---|
| null/None | x != null |
if x:(隐式) |
| 空字符串 | s.Length > 0 |
if s:(隐式) |
| 零值 | n != 0 |
if n:(隐式) |
| 空集合 | list.Count > 0 |
if lst:(隐式) |
C# 得写一堆 != null、Length > 0、Count > 0,Python 直接 if x: 一个搞定。但要注意——Python 的 if x: 判断逻辑和 C# 不同,空字符串、0、空列表都是 False。
模式匹配
C# 9+ 引入了强大的模式匹配:
object obj = 5;
// 类型模式
if (obj is int n)
{
Console.WriteLine($"是整数: {n}");
}
// 属性模式
if (obj is string { Length: > 0 } s)
{
Console.WriteLine($"非空字符串: {s}");
}
// switch 表达式
string GetCategory(int score) => score switch
{
>= 90 => "优秀",
>= 80 => "良好",
>= 60 => "及格",
_ => "不及格"
};
Python 3.10+ 也有了 match-case:
obj = 5
# 基本匹配
match obj:
case int() as n:
print(f"是整数: {n}")
case str() as s if len(s) > 0:
print(f"非空字符串: {s}")
case _:
print("其他类型")
# 守卫条件(guard)
match score:
case s if s >= 90:
category = "优秀"
case s if 80 <= s < 90:
category = "良好"
case s if 60 <= s < 80:
category = "及格"
case _:
category = "不及格"
Python 的 match-case 和 C# 的 switch 表达式很像,但 Python 的更灵活——支持守卫条件(guard),可以写复杂的匹配逻辑。
模式匹配进阶
序列模式(Sequence Pattern)
Python 的序列模式可以匹配列表、元组等序列:
def describe_point(point):
match point:
case (0, 0):
print("原点")
case (x, 0):
print(f"在 x 轴上,x = {x}")
case (0, y):
print(f"在 y 轴上,y = {y}")
case (x, y):
print(f"点 ({x}, {y})")
case _:
print("不是二维点")
# 使用
describe_point((0, 0)) # 原点
describe_point((5, 0)) # 在 x 轴上,x = 5
describe_point((3, 4)) # 点 (3, 4)
C# 对比:
void DescribePoint((int x, int y) point) => point switch
{
(0, 0) => Console.WriteLine("原点"),
(var x, 0) => Console.WriteLine($"在 x 轴上,x = {x}"),
(0, var y) => Console.WriteLine($"在 y 轴上,y = {y}"),
(var x, var y) => Console.WriteLine($"点 ({x}, {y})"),
_ => Console.WriteLine("不是二维点"),
};
映射模式(Mapping Pattern)
Python 独有的映射模式,可以匹配字典:
match command:
case {"action": "quit"}:
print("退出")
case {"action": "move", "direction": direction}:
print(f"向 {direction} 移动")
case {"action": "attack", "target": target, "weapon": weapon}:
print(f"用 {weapon} 攻击 {target}")
case _:
print("未知命令")
# 使用
command = {"action": "move", "direction": "north"}
match command:
case {"action": "move", "direction": direction}:
print(f"向 {direction} 移动") # 输出: 向 north 移动
C# 没有直接的映射模式,需要用属性模式或 if 语句:
// C# 需要用属性模式
record Command(string Action, string? Direction, string? Target, string? Weapon);
void HandleCommand(Command cmd) => cmd switch
{
{ Action: "quit" } => Console.WriteLine("退出"),
{ Action: "move", Direction: var dir } => Console.WriteLine($"向 {dir} 移动"),
{ Action: "attack", Target: var t, Weapon: var w } => Console.WriteLine($"用 {w} 攻击 {t}"),
_ => Console.WriteLine("未知命令"),
};
OR 模式
Python 和 C# 都支持 OR 模式,但语法不同:
# Python
match status_code:
case 200 | 201 | 204:
print("成功")
case 400 | 401 | 403:
print("客户端错误")
case 500 | 502 | 503:
print("服务器端错误")
case _:
print("其他状态码")
# 命令别名
match command:
case "quit" | "exit" | "q":
sys.exit()
case "help" | "h" | "?":
show_help()
// C#
string GetCategory(int statusCode) => statusCode switch
{
200 or 201 or 204 => "成功",
400 or 401 or 403 => "客户端错误",
500 or 502 or 503 => "服务器端错误",
_ => "其他状态码"
};
星号模式(Star Pattern)
Python 的星号模式可以匹配序列的剩余部分:
match items:
case []:
print("空列表")
case [x]:
print(f"单个元素: {x}")
case [x, y]:
print(f"两个元素: {x}, {y}")
case [first, *middle, last]:
print(f"首: {first}, 中间: {middle}, 尾: {last}")
case [*all]:
print(f"所有元素: {all}")
# 使用
items = [1, 2, 3, 4, 5]
match items:
case [first, *middle, last]:
print(f"首: {first}, 中间: {middle}, 尾: {last}")
# 输出: 首: 1, 中间: [2, 3, 4], 尾: 5
C# 没有直接的星号模式,需要用 LINQ:
// C# 需要用 LINQ
var items = new[] { 1, 2, 3, 4, 5 };
if (items.Length >= 2)
{
var first = items[0];
var last = items[^1];
var middle = items[1..^1];
Console.WriteLine($"首: {first}, 中间: [{string.Join(", ", middle)}], 尾: {last}");
}
类模式(Class Pattern)
Python 的类模式可以匹配对象的属性:
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
def describe(point):
match point:
case Point(x=0, y=0):
print("原点")
case Point(x=x, y=0):
print(f"在 x 轴上: {x}")
case Point(x=0, y=y):
print(f"在 y 轴上: {y}")
case Point(x=x, y=y):
print(f"点 ({x}, {y})")
# 使用
describe(Point(0, 0)) # 原点
describe(Point(5, 0)) # 在 x 轴上: 5
C# 对比:
// C# 用 record 或类
record Point(int X, int Y);
string Describe(Point point) => point switch
{
{ X: 0, Y: 0 } => "原点",
{ X: var x, Y: 0 } => $"在 x 轴上: {x}",
{ X: 0, Y: var y } => $"在 y 轴上: {y}",
{ X: var x, Y: var y } => $"点 ({x}, {y})",
};
嵌套模式
Python 支持嵌套的模式匹配:
match command:
case ("move", ("north" | "south" | "east" | "west") as direction):
print(f"向 {direction} 移动")
case ("attack", {"target": target, "weapon": weapon}):
print(f"用 {weapon} 攻击 {target}")
case _:
print("未知命令")
# 使用
command = ("move", "north")
match command:
case ("move", ("north" | "south" | "east" | "west") as direction):
print(f"向 {direction} 移动") # 输出: 向 north 移动
综合对比表
| 特性 | C# | Python |
|---|---|---|
| 类型模式 | obj is int n |
case int() as n: |
| 值模式 | case 42: |
case 42: |
| 关系模式 | > 0, < 10 |
守卫条件 if x > 0 |
| 属性模式 | { Length: > 0 } |
不支持(需守卫条件) |
| 列表/元组模式 | 元组解构 (a, b) |
case [a, b]: |
| 字典模式 | 不支持 | case {"key": val}: |
| OR 模式 | case 1 or 2: |
case 1 | 2: |
| 求反模式 | not null |
case None: |
| switch 表达式 | x switch { ... } |
match x: case ... |
| 守卫条件 | when x > 0 |
case _ if x > 0: |
| 弃元 | _ |
_ |
| 嵌套解构 | 支持 | 支持 |
| 范围匹配 | >= 0 and <= 100 |
case _ if 0 <= x <= 100: |
条件表达式的"骚操作"
Python 独有的条件表达式技巧:
# 1. and/or 短路求值
x = None
value = x or "default" # 如果 x 为 None,用 "default"
# 2. 条件赋值
result = "正数" if x > 0 else "非正数"
# 3. 多条件链式
if 0 < x < 100 and x != 50:
print("满足条件")
# 4. 列表推导式中的条件
numbers = [1, 2, 3, 4, 5]
even = [x for x in numbers if x % 2 == 0] # [2, 4]
# 5. any() 和 all()
numbers = [1, 2, 3, 4, 5]
has_even = any(x % 2 == 0 for x in numbers) # True
all_positive = all(x > 0 for x in numbers) # True
Python 的 and/or 不仅能做逻辑运算,还能用来做默认值处理——x or "default" 比 C# 的 x ?? "default" 更简洁。
设计哲学
C# 的哲学是显式结构——大括号明确代码块边界,条件表达式必须是布尔类型,模式匹配功能强大。
Python 的哲学是缩进即结构——缩进就是代码块的边界,鸭子类型让任何对象都可以作为条件,elif 比 else if 更简洁。
C# 像是给你一个明确的"框架",你得在框架里填内容; Python 像是给你一张白纸,你用缩进来画出结构。
更深层的原因:
-
C# 的条件表达式必须返回布尔类型,这是类型安全的体现
-
Python 的条件表达式可以是任何对象,这是鸭子类型的体现——只要"看起来像布尔"就行
真实场景:在处理 API 响应时,Python 的真值判断非常方便:
# 检查响应是否成功
response = requests.get("https://api.example.com")
if response: # 状态码 200-399 为 True
data = response.json()
else:
print(f"请求失败: {response.status_code}")
C# 得这样写:
var response = await httpClient.GetAsync("https://api.example.com");
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
}
else
{
Console.WriteLine($"请求失败: {response.StatusCode}");
}
迁移指南:C# 开发者最容易犯的错
-
忘记 elif 是一个关键字:不是
else if,是elif -
以为
if x:只检查 None:空字符串、0、空列表都是 False -
过度嵌套条件:Python 支持链式比较
0 < x < 10 -
忘记
and/or返回实际值:不一定是布尔值 -
以为 Python 没有模式匹配:Python 3.10+ 有 match-case
推荐工具:用 VS Code + Python 插件,它会帮你检查条件表达式的常见错误。
坑点提醒
elif 不是 else if——Python 的 elif 是一个关键字:
if x > 0:
print("正数")
elif x < 0: # 不是 else if
print("负数")
else:
print("零")
条件表达式的优先级——不要嵌套太多层:
# 不要这样写(可读性差)
result = "正数" if x > 0 else "负数" if x < 0 else "零"
真值判断的陷阱——空值、零值都是 False:
if 0: # False
print("0 是 True")
if "": # False
print("空字符串是 True")
if []: # False
print("空列表是 True")
if None: # False
print("None 是 True")
一句话总结
Python 的
elif比 C# 的else if少打一个空格,这就是 Python 的"懒人哲学"。
下一篇咱们来聊聊循环结构——Python 的 for...else 是个"反直觉"的设计,循环没被 break 就执行 else。
📦 代码仓库:
💬 欢迎点赞、收藏、转发,你的支持是我持续创作的动力!
更多推荐
所有评论(0)