Pythonoop教程:类与实例

Python是一门非常灵活的语言,它同时支持面向过程函数式面向对象(OOP)等多种编程范式。
当项目规模逐渐扩大时,oop便成了组织复杂代码、提升可维护性的利器。而在OOP的世界里,类(Class)实例(Instance) 是两个最基础、也最必须掌握的概念。


1. 生活类比:图纸与实物

想弄清楚类和实例的区别,不妨先离开代码,看看生活中的例子:

  • 汽车设计图纸就像一个「类」——它定义了“一辆车应该有的属性”(品牌、颜色、轮子数量)和“一辆车能执行的动作”(启动、刹车、鸣笛)。
  • 楼下停着的那辆红色特斯拉Model 3则是一个「实例」——它是按照图纸制造出来的、看得见摸得着的具体产品,拥有自己独一无二的车牌号和颜色,能够真实地执行图纸上描述的所有动作。

把这种思维平移到编程里:

  • 是抽象的数据 + 行为模板,数据称为属性,行为称为方法
  • 实例是根据模板生成的具体对象,每个实例的属性可以各自不同,但它们共享类中定义的所有方法。

2. 定义你的第一个类

在Python中,使用 class 关键字来定义类。
现代Python(3.x)中,所有类默认都继承自 object,完全不需要显式地写出 (object),一个最简的写法如下:

# 定义一个没有任何属性和方法的“空”学生类
class Student:
    pass   # pass是占位符,用来保证语法正确

虽然 Student 类目前什么也做不了,但它已经是一个合法的“模板”了。


3. 由模板生成实例

创建实例的方式非常简单,就像调用函数一样:类名 + 圆括号

# 用Student类“生”出两个具体的学生
bart = Student()
lisa = Student()

# 每个实例在内存中都有独立的位置
print(bart)    # <__main__.Student object at 0x7f...>
print(lisa)    # <__main__.Student object at 0x7f...>

# 类本身是一个“类型对象”
print(Student) # <class '__main__.Student'>

可以看到,bartlisa 都是 Student 类的实例,但它们占据不同的内存地址,是完全独立的两个对象。


4. 用 __init__ 赋予初始属性

一个空的实例显然没什么用。我们希望在创建实例的同时就让它拥有一些属性(比如姓名、成绩)。这就需要用到Python中的一个“魔法方法”—— __init__

__init__ 方法会在实例被创建后自动调用,因此常被称为构造函数初始化方法。注意命名:前后各有两个下划线。

class Student:
    # self 必须放在参数的第一个位置,它代表“当前正在被创建的实例”
    def __init__(self, name, score):
        # 通过 self.xxx 绑定的属性,会成为该实例的专属属性
        self.name = name
        self.score = score

编写时的三个要点:

  1. self 参数必须明确写出,但调用时Python会自动传入,我们不需要手动给它赋值。
  2. __init__ 的名字不能错,多一个或少一个下划线都会失效。
  3. 创建实例时,除了 self 之外的参数必须与定义一一对应。

测试一下:

bart = Student('Bart Simpson', 59)
print(bart.name)   # Bart Simpson
print(bart.score)  # 59

每个实例的 namescore 都是独立保存的,互不干扰。


5. 让实例具备“行为”:实例方法

除了静态的属性,我们通常还需要让实例能够执行某些操作,这些操作就叫方法
最常用的方法类型是实例方法,它的第一个参数同样必须是 self,这样才能访问当前实例的属性。

5.1 定义打印成绩的方法

class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score

    # 实例方法:利用 self 拿到当前实例的 name 和 score
    def print_score(self):
        print(f"{self.name} 的分数是 {self.score}")

5.2 调用方法

调用时依然不需要传递 self,Python 会自动将调用者(如 bart)绑定到 self 上:

bart = Student('Bart Simpson', 59)
bart.print_score()   # Bart Simpson 的分数是 59

6. 面向对象的核心优势:数据封装

在没有对象的编程中,数据与操作数据的函数往往是分离的,这会增加数据被意外修改或误用的风险。
数据封装则把“属性”和“操作这些属性的方法”打包在一起,从逻辑上形成了一个自包含的单元,外部使用者只需要调用方法,不需要直接触碰底层数据。

6.1 封装一个成绩等级计算功能

我们可以在 Student 类中增加一个 get_grade 方法,它根据分数返回等级。用户完全不用关心内部的判断逻辑。

class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score

    def print_score(self):
        print(f"{self.name} 的分数是 {self.score}")

    def get_grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'

6.2 外部调用体验

lisa = Student('Lisa Simpson', 99)
bart = Student('Bart Simpson', 59)

# 只需一行调用,内部细节被完美隐藏
print(lisa.name, lisa.get_grade())   # Lisa Simpson A
print(bart.name, bart.get_grade())   # Bart Simpson C

这样做的好处是:如果将来等级评定的规则发生改变,我们只需要修改 get_grade 方法的内部实现,所有使用该方法的地方都会自动生效。


7. Python 的“特技”:动态属性

与 Java、C++ 等语言不同,Python 允许在运行时给某个特定实例动态地添加、修改或删除属性。这些属性仅属于该实例,不会影响类和其他实例。

bart = Student('Bart Simpson', 59)
lisa = Student('Lisa Simpson', 87)

# 只给 bart 增加一个 age 属性
bart.age = 8
print(bart.age)   # 8

# lisa 并没有这个属性,访问会报错
print(lisa.age)   # AttributeError: 'Student' object has no attribute 'age'

🧠 小提示
动态属性虽然灵活,但过度使用会让代码逻辑难以追踪,也容易引发隐蔽的bug。
如果某个属性是所有实例都应该有的,务必把它放在 __init__ 里统一初始化。


8. 代码风格与最佳实践

写出一份“能用”的代码只是开始,写出“易读、易维护”的代码才是专业的表现。
下面是一些Python社区普遍遵循的规范。

8.1 命名约定

  • 类名:采用 PascalCase(大驼峰式),例如 StudentUniversityStudent
  • 函数名、方法名、变量名:采用 snake_case(小写下划线式),例如 bart_simpsonprint_score

8.2 善用类型提示与文档字符串

Python 3.5+ 支持类型提示,虽然它并不在运行时强制检查,却能显著提升代码可读性,同时也能让 IDE 的自动补全更加智能。
配合注释完善的文档字符串,你的类就会像一本自带说明书的小工具。

class Student:
    """学生类,管理学生的基本信息和成绩"""

    def __init__(self, name: str, score: float) -> None:
        """
        初始化学生实例

        Args:
            name: 学生姓名
            score: 考试分数
        """
        self.name = name
        self.score = score

    def print_score(self) -> None:
        """打印姓名和成绩"""
        print(f"{self.name} 的分数是 {self.score}")

    def get_grade(self) -> str:
        """
        根据分数返回等级

        Returns:
            'A': 90分及以上
            'B': 60-89分
            'C': 60分以下
        """
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'

9. 小结

通过本文,我们快速走完了Pythonoop的启蒙之路,核心要点总结如下:

  1. 是抽象的模板,实例是具体的产物;
  2. __init__ 构造函数负责为每个实例设置独立的初始属性;
  3. 实例方法通过 self 访问实例数据,实现对象的行为;
  4. 数据封装将属性和方法绑定在一起,提升代码的安全性与可维护性;
  5. 动态属性赋予了Python独特的灵活性,但应谨慎使用。

掌握了类和实例,你就拥有了构建更复杂OOP结构的稳固地基(继承、多态、私有属性等),我们会在接下来的文章中继续深入,敬请期待!