C#转Python第3.1篇:Python 的 class 没有访问修饰符?面向对象的另一条路

在 C# 里定义类,就像写一份蓝图------构造函数、属性、方法、字段,每个都有明确的职责。

在 Python 里定义类,就像搭积木------__init__ 初始化,self 代表自己,属性想放哪放哪。

当我第一次写 Python 类发现没有 new 关键字的时候,我的内心是:"这对象怎么创建出来的?"

但写多了之后发现,Python 的类定义就是这么"随性"------约定大于约束。

基础语法对比

C# 版本:

复制代码
public class Person
{
    // 字段
    private string name;
    private int age;

    // 构造函数
    public Person(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    // 属性
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public int Age
    {
        get { return age; }
        set { age = value; }
    }

    // 方法
    public string Greet()
    {
        return $"Hello, I'm {name}";
    }
}

// 使用
var person = new Person("Alice", 25);
Console.WriteLine(person.Greet());

Python 版本:

复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def greet(self):
        return f"Hello, I'm {self.name}"

# 使用
person = Person("Alice", 25)
print(person.greet())

对比一下:

对比项 C# Python
类定义 public class MyClass { } class MyClass:
构造函数 public MyClass() def __init__(self):
self/this 隐式 this 显式 self(必须第一个参数)
属性 需要定义 get/set 直接赋值就行
字段 必须声明类型 不需要声明
访问修饰符 public/private/protected 没有(约定 _ 开头为私有)
实例化 new MyClass() MyClass()(没有 new)

C# 的类像写合同,每一条都清清楚楚;Python 的类像搭积木,放哪都行。

构造函数与初始化

C# 版本:

复制代码
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    // 默认构造函数
    public Person() { }

    // 带参数的构造函数
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    // 静态工厂方法
    public static Person Create(string name)
    {
        return new Person(name, 0);
    }

    // 构造函数链
    public Person(string name) : this(name, 0) { }
}

Python 版本:

复制代码
class Person:
    def __init__(self, name="", age=0):
        self.name = name
        self.age = age

    @classmethod
    def create(cls, name):
        return cls(name, 0)

    # Python 没有构造函数重载,用默认参数
    # 或者用 @classmethod 或 @staticmethod

C# 支持构造函数重载,Python 用默认参数替代。

属性 vs 直接赋值

C# 版本:

复制代码
public class Person
{
    private string name;
    private int age;

    // 完整属性
    public string Name
    {
        get { return name; }
        set
        {
            if (string.IsNullOrEmpty(value))
                throw new ArgumentException("名字不能为空");
            name = value;
        }
    }

    // 自动属性
    public int Age { get; set; }

    // 只读属性
    public string Description => $"{Name} is {Age} years old";
}

Python 版本:

复制代码
class Person:
    def __init__(self, name, age):
        self._name = name  # 约定为私有
        self.age = age

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        if not value:
            raise ValueError("名字不能为空")
        self._name = value

    @property
    def description(self):
        return f"{self.name} is {self.age} years old"

C# 的属性是语言特性,Python 用 @property 装饰器模拟。

类变量 vs 实例变量

C# 版本:

复制代码
public class Person
{
    // 静态字段(类变量)
    public static int InstanceCount = 0;

    // 实例字段
    public string Name { get; set; }

    public Person(string name)
    {
        Name = name;
        InstanceCount++;  // 每次创建实例都加1
    }
}

Console.WriteLine(Person.InstanceCount);  // 0
var p1 = new Person("Alice");
Console.WriteLine(Person.InstanceCount);  // 1
var p2 = new Person("Bob");
Console.WriteLine(Person.InstanceCount);  // 2

Python 版本:

复制代码
class Person:
    # 类变量(所有实例共享)
    instance_count = 0

    def __init__(self, name):
        self.name = name  # 实例变量
        Person.instance_count += 1

print(Person.instance_count)  # 0
p1 = Person("Alice")
print(Person.instance_count)  # 1
p2 = Person("Bob")
print(Person.instance_count)  # 2

C# 用 static 关键字,Python 直接在类级别定义变量。

魔术方法(Dunder Methods)

C# 版本:

复制代码
public class Vector
{
    public double X { get; }
    public double Y { get; }

    public Vector(double x, double y)
    {
        X = x;
        Y = y;
    }

    // 运算符重载
    public static Vector operator +(Vector a, Vector b)
    {
        return new Vector(a.X + b.X, a.Y + b.Y);
    }

    // ToString 重写
    public override string ToString()
    {
        return $"({X}, {Y})";
    }

    // 相等性比较
    public override bool Equals(object obj)
    {
        if (obj is Vector other)
            return X == other.X && Y == other.Y;
        return false;
    }

    public override int GetHashCode()
    {
        return HashCode.Combine(X, Y);
    }
}

Python 版本:

复制代码
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    # 运算符重载
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    # 字符串表示
    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

    def __str__(self):
        return f"({self.x}, {self.y})"

    # 相等性比较
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __hash__(self):
        return hash((self.x, self.y))

C# 用 operator 关键字重载运算符,Python 用魔术方法(__add____repr__ 等)。

dataclass(Python 3.7+)

Python 3.7+ 引入了 @dataclass,大幅简化类的定义:

复制代码
from dataclasses import dataclass

@dataclass
class Person:
    name: str
    age: int
    email: str = ""

    def greet(self):
        return f"Hello, I'm {self.name}"

# 自动生成 __init__、__repr__、__eq__ 等方法
person = Person("Alice", 25, "alice@example.com")
print(person)  # Person(name='Alice', age=25, email='alice@example.com')

C# 9+ 的 record 类似:

复制代码
public record Person(string Name, int Age, string Email = "");

var person = new Person("Alice", 25);
Console.WriteLine(person);  // Person { Name = Alice, Age = 25, Email =  }

设计哲学

C# 的类是"蓝图模式"------先定义类型,再创建实例,类型安全,编译检查。

Python 的类是"搭积木模式"------属性想放哪放哪,方法可以动态添加,灵活但需要自律。

C# 的类像是写建筑图纸,每根钢筋都有编号; Python 的类像是搭乐高,怎么搭都行,但得自己保证不塌。

坑点提醒

忘记 self------Python 类方法的第一个参数必须是 self:

复制代码
class Person:
    def greet():  # 错误!缺少 self
        return "Hello"

# 正确写法
class Person:
    def greet(self):
        return "Hello"

类变量的陷阱------可变对象共享:

复制代码
class MyClass:
    items = []  # 类变量,所有实例共享!

a = MyClass()
b = MyClass()
a.items.append(1)
print(b.items)  # [1]!b 也受影响了

# 正确写法:在 __init__ 中初始化
class MyClass:
    def __init__(self):
        self.items = []  # 实例变量

self 不是关键字------只是约定:

复制代码
class Person:
    def __init__(me, name):  # 用 me 也行,但不推荐
        me.name = name

迁移指南:C# 开发者最容易犯的错

这一章节的内容比较特殊,迁移指南会在后续文章中详细讨论。

一句话总结

C# 的类是"蓝图模式",Python 的类是"搭积木模式"------都能搭出漂亮的建筑,但风格完全不同。

下一篇咱们来聊聊访问修饰符------Python 的"君子协定" vs C# 的 private/protected/public。


📦 示例代码:C# 转 Python 全系列配套练习代码(含 48 章示例)

💬 欢迎点赞、收藏、转发,你的支持是我持续创作的动力!

相关推荐
Wzx1980122 小时前
python沙箱和docker沙箱你选对了吗?
开发语言·python·docker
Python私教2 小时前
签名 URL 刷新导致审批失效?别急着删掉所有 query
python·安全
牧羊人.3332 小时前
Python 办公自动化从入门到入土|09 数据容器之字典
开发语言·python
小僧景贤2 小时前
嵌入式C语言 第二篇:基础语法|嵌入式C与标准C的核心差异
c语言·开发语言·嵌入式c语言
Zane19942 小时前
类变量与实例变量:一个共享列表引发的线上事故
后端·python
阿pin2 小时前
Android随笔-AIDL
android·开发语言·aidl
Python私教2 小时前
一次性批准令牌:挡住旧授权误发新版本的工程设计
python·安全
for_ever_love__3 小时前
python基础语法学习: 数据容器
windows·python·学习
aiqianji3 小时前
文风接近真人的AI生成短篇小说软件有哪些?
人工智能·python