在 C# 里,声明一个变量就像是给银行开户——你得先告诉银行(编译器)这个账户是什么类型:是储蓄账户(int)还是信用卡账户(string)?
在 Python 里,声明变量就像是往兜里塞东西——你直接塞进去就行了,至于是什么类型...解释器会自己看。
当我第一次写 x = 5 然后发现居然不需要声明类型的时候,我的内心是:"这也行?那我之前写的那些 int x = 5; 算什么?"
后来我才明白,Python 的变量只是一个"标签",可以贴在任何对象上。而 C# 的变量是一个"容器",只能装特定类型的东西。
今天咱们来聊聊变量声明和类型系统——C# 的"类型安全" vs Python 的"动态类型"。
变量声明基础对比
C# 版本:
// 显式类型声明
int x = 5;
string name = "张三";
double price = 9.99;
bool isTrue = true;
// 类型推断(var)
var y = 10; // 编译器推断为 int
var msg = "hello"; // 编译器推断为 string
// 动态类型
dynamic z = 5; // 运行时才确定类型
z = "hello"; // 可以改变类型
Python 版本:
# Python 天生就是"推断"的
x = 5 # int
name = "张三" # str
price = 9.99 # float
is_true = True # bool
# 也可以加类型注解(但解释器不理你)
y: int = 10
name: str = "李四"
| 对比项 | C# | Python |
|---|---|---|
| 变量声明 | int x = 5; | x = 5 |
| 类型声明 | 必须(或用 var) | 可选(类型注解) |
| 类型推断 | var x = 5; | 天生就是推断的 |
| 动态类型 | dynamic x = 5; | 所有变量都是动态的 |
| 常量 | const int X = 5; | 没有 const,用全大写命名 |
为什么 Python 不需要声明类型?
因为 Python 是动态类型语言,变量的类型在运行时确定,而不是编译时。变量只是一个"标签",可以贴在任何对象上。
x = 5 # x 贴在整数 5 上
x = "hello" # x 现在贴在字符串 "hello" 上
x = [1, 2] # x 现在贴在列表上
这就像:C# 的变量是"专用抽屉",只能放一种东西;Python 的变量是"便利贴",可以贴在任何东西上。
类型注解:C# 程序员的安慰剂
C# 的类型注解是强制的:
int x = 5;
string name = "hello";
// var 是语法糖,编译器还是知道类型
var y = 10; // y 是 int
// 接口和泛型
IEnumerable<int> numbers = new List<int> { 1, 2, 3 };
Python 的类型注解是可选的,解释器根本不理你:
x: int = 5
name: str = "hello"
# 但 IDE 会用它来做智能提示
def greet(name: str) -> str:
return f"Hello, {name}"
# 泛型(Python 3.12+)
from typing import TypeVar
T = TypeVar('T')
def first(lst: list[T]) -> T:
return lst[0]
| 特性 | C# | Python |
|---|---|---|
| 类型注解目的 | 编译检查 | IDE 提示 + 文档 |
| 类型检查时机 | 编译时 | 运行时(忽略注解) |
| 类型安全 | 强制 | 自愿 |
| 错误发现 | 编译时 | 运行时 |
Python 的类型注解就像考试时老师说"可以翻书,但翻了也不一定有用"。
真实场景:Python 的类型注解主要是给 IDE 和 类型检查工具(如 mypy)用的。在大厂的 Python 项目里,类型注解是强制的,因为代码量太大,没有类型检查会出人命。
常量和只读变量
C# 有真正的常量:
// 编译时常量
const double Pi = 3.14159;
const string Greeting = "Hello";
// 运行时常量(只读)
readonly int MaxRetries = 3;
Python 没有 const,只有约定:
# 用全大写命名约定
PI = 3.14159
GREETING = "Hello"
# 这只是一个约定,你还是可以修改它
PI = 999 # 不会报错,但会被鄙视
# 如果真想保护,可以用 dataclass
from dataclasses import dataclass
@dataclass(frozen=True)
class Config:
pi: float = 3.14159
greeting: str = "Hello"
Python 的"常量"全靠自觉,改了也不会报错,但会被同事鄙视。
为什么 Python 不支持 const?
因为 Python 的设计哲学是**"成年人应该被信任"**。它假设你知道自己在做什么,不需要语言层面的强制约束。
变量作用域
C# 的作用域很清晰——大括号内有效:
{
int x = 5; // x 在这个块内有效
}
// x = 10; // 编译错误:x 不存在
Python 的作用域遵循 LEGB 规则(Local → Enclosing → Global → Built-in):
x = "global" # 全局变量
def outer():
x = "enclosing" # 外层函数变量
def inner():
x = "local" # 局部变量
print(x) # 输出: local
inner()
# 如果想修改全局变量
counter = 0
def increment():
global counter
counter += 1
Python 的作用域比 C# 复杂——它会一层层往外找变量,找到哪个用哪个。
为什么 Python 要用 LEGB 规则?
因为 Python 的函数可以嵌套定义,闭包是常见模式。LEGB 规则让内层函数可以访问外层函数的变量,这是实现闭包的基础。
类型转换
// C# 类型转换
int x = 5;
double y = (double)x; // 显式转换
string s = x.ToString(); // 转字符串
int z = int.Parse("123"); // 字符串转 int
int w = Convert.ToInt32("456"); // Convert 方法
# Python 类型转换
x = 5
y = float(x) # 转浮点数
s = str(x) # 转字符串
z = int("123") # 字符串转 int
w = bool(0) # 转布尔(0 是 False)
C# 有多种转换方式(强转、Parse、Convert),Python 就简单粗暴——int()、str()、float(),一个函数搞定。
真实案例:C# 的 int.Parse("abc") 会抛异常,而 Python 的 int("abc") 也会抛异常。但 C# 还有 int.TryParse() 可以安全转换,Python 没有这个,你得用 try-except。
设计哲学
C# 的哲学是类型安全——编译器帮你检查类型错误,显式声明让代码更清晰,适合大型项目和团队协作。
Python 的哲学是动态类型——类型是值的属性,不是变量的属性,鸭子类型让代码更灵活,适合快速开发。
C# 像是给每个变量办了身份证,随时可以查验; Python 像是让变量自由流动,需要的时候再看它是什么。
更深层的原因:
- C# 需要编译器提前知道类型,才能生成高效的机器码
- Python 是解释执行的,不需要提前知道类型,运行时动态查找方法
迁移指南:C# 开发者最容易犯的错
- 以为没有类型就是"不安全":Python 有类型注解,只是可选
- 忘记
global关键字:在函数里修改全局变量需要global - 以为变量声明后类型固定:Python 变量可以随时换类型
- 过度使用类型注解:Python 不需要像 C# 那样到处写类型
- 以为
None是关键字:Python 里None是一个对象,不是关键字
推荐工具:用 VS Code + Pylance 插件,可以获得类似 ReSharper 的类型提示体验。
坑点提醒
类型注解不等于类型检查——写了注解解释器也不理你:
x: int = "hello" # 不会报错!
print(type(x)) # <class 'str'>
变量可以改变类型——C# 的 dynamic 也没这么自由:
x = 5
print(type(x)) # <class 'int'>
x = "hello"
print(type(x)) # <class 'str'>
常量约定不是强制的——改了也不会报错:
MAX_SIZE = 100
MAX_SIZE = 999 # 不会报错,但违反约定
作用域陷阱——函数内赋值不会修改全局变量:
x = 10
def modify():
x = 20 # 这是新变量,不是修改全局的 x
print(x) # 20
modify()
print(x) # 还是 10!
一句话总结
Python 的类型注解就是给 C# 程序员的安慰剂——你可以写,但解释器不一定理你。
下一篇咱们来聊聊基本数据类型——C# 的 int 有大小限制,Python 的 int 却能无限大。还有,Python 的 True + True 居然等于 2?!
关注公众号「半亩码田」,获取更多 C# vs Python 对比内容。
回复「C#vsPython」获取本系列完整 demo 代码仓库。