类与对象|第五部分:面向对象编程 (Object-Oriented Programming - OOP)

发布于 2025-09-11 分类: Python
系列文章: Python全方位教程
第 1 部分: Python语言概览|第一部分:Python入门与环境搭建 (Python Foundations) 第 2 部分: 搭建开发环境|第一部分:Python入门与环境搭建 (Python Foundations) 第 3 部分: Python基本语法与规范|第一部分:Python入门与环境搭建 (Python Foundations) 第 4 部分: 数据类型深入解析|第二部分:Python核心数据类型与运算符 (Core Data Types & Operators) 第 5 部分: 运算符大全|第二部分:Python核心数据类型与运算符 (Core Data Types & Operators) 第 6 部分: 条件与循环|第三部分:流程控制与数据结构操作 (Control Flow & Data Structures Manipulation) 第 7 部分: 数据结构高级操作|第三部分:流程控制与数据结构操作 (Control Flow & Data Structures Manipulation) 第 8 部分: 函数|第四部分:函数、模块与代码组织 (Functions, Modules & Code Organization) 第 9 部分: 模块与包|第四部分:函数、模块与代码组织 (Functions, Modules & Code Organization) 第 10 部分: 类与对象|第五部分:面向对象编程 (Object-Oriented Programming - OOP) (当前) 第 11 部分: OOP核心特性|第五部分:面向对象编程 (Object--Oriented Programming - OOP) 第 12 部分: 高级OOP主题|第五部分:面向对象编程 (Object-Oriented Programming - OOP) 第 13 部分: 迭代与生成|第六部分:高级Python编程 (Advanced Python) 第 15 部分: 内存管理与性能|第六部分:高级Python编程 (Advanced Python) 第 16 部分: 文件与目录操作|第七部分:Python标准库精选 (The Standard Library) 第 17 部分: 数据处理与序列化|第七部分:Python标准库精选 (The Standard Library) 第 18 部分: 网络与并发编程|第七部分:Python标准库精选 (The Standard Library) 第 20 部分: 系统交互|第七部分:Python标准库精选 (The Standard Library) 第 21 部分: 数据科学与分析入门|第八部分:Python生态与实战应用 (Ecosystem & Applications) 第 22 部分: Web开发入门|第八部分:Python生态与实战应用 (Ecosystem & Applications) 第 23 部分: GUI编程入门|第八部分:Python生态与实战应用 (Ecosystem & Applications) 第 24 部分: 图像处理入门|第八部分:Python生态与实战应用 (Ecosystem & Applications) 第 25 部分: 自动化脚本|第八部分:Python生态与实战应用 (Ecosystem & Applications) 第 26 部分: Python备忘单 (Cheatsheet)|第九部分:附录与资源 (Appendix & Resources) 第 27 部分: 常见面试题与解答|第九部分:附录与资源 (Appendix & Resources) 第 28 部分: 官方文档与其他学习资源链接|第九部分:附录与资源 (Appendix & Resources)

欢迎来到Python世界的“创世纪”!在此之前,我们一直在使用Python“神”已经为我们创造好的事物:字符串 str、列表 list、字典 dict 等。我们像一个使用者,遵循着它们的规则。

但你是否曾想过,如果我也能创造属于自己的、全新的数据类型呢?比如,一个“汽车”类型,它有自己的“颜色”和“品牌”(数据),还能执行“启动引擎”、“加速”等操作(行为)。或者一个“用户”类型,它有“用户名”和“等级”,还能“登录”和“发帖”。

这就是**面向对象编程(OOP)**的核心思想:将数据和操作这些数据的函数(我们称之为方法)捆绑在一起,形成一个独立的、有机的整体——对象。

这不仅仅是一种新的语法,更是一种全新的世界观。你将从一个听从指令的“过程执行者”,转变为一个创造万物的“上帝”,在你的代码世界里设计、创造并指挥无数个相互协作的对象。让我们开始创造你的第一个“物种”吧!

10.1 OOP基本概念 (类, 对象, 实例)

在进入代码之前,我们必须理解三个核心概念,它们是OOP世界的基石。

  • 类 (Class): 蓝图或模板。它定义了一个“物种”应该具有的共同属性(数据)和行为(方法)。例如,“汽车”这个类,它的蓝图上会写着:所有汽车都应该有“颜色”、“品牌”属性,都应该能“启动”和“刹车”。类本身不是一个实体,它只是一种规范。

  • 对象 (Object): 根据蓝图创造出来的实体。一辆红色的法拉利、一辆蓝色的福特,它们都是“汽车”类的具体对象。每个对象都拥有类所定义的属性和方法,但它们的属性值(比如颜色)可以是不同的。

  • 实例 (Instance): “对象”的另一种称呼。当我们说“my_carCar 类的一个实例”时,意思和“my_carCar 类的一个对象”完全一样。实例化就是根据类创建对象的过程。

一句话总结:我们定义一个(蓝图),然后通过这个类来实例化出很多个对象(实体)。

10.2 定义类 (class 关键字)

在Python中,我们使用 class 关键字来定义一个类。按照惯例(PEP 8规范),类名通常使用驼峰命名法 (PascalCase),即每个单词的首字母都大写。

# 定义一个最简单的“猫”类
# 这张蓝图目前是空的,但它已经是一个合法的类了
class Cat:
    pass # pass 是一个占位符,表示什么都不做

# 实例化:根据 Cat 类的蓝图,创建两个具体的猫对象
cat1 = Cat()
cat2 = Cat()

print(cat1) # 输出: <__main__.Cat object at 0x...> (一个Cat对象,以及它在内存中的地址)
print(cat2) # 输出: <__main__.Cat object at 0x...> (另一个Cat对象,地址不同)

10.3 构造函数 (__init__) 与实例方法

我们空的“猫”蓝图还不够实用。我们希望每只猫被“创造”出来的时候,就应该有自己的名字和年龄。这就要用到一个非常特殊的“魔法方法”——__init__

  • __init__(self, ...) (构造函数/初始化方法): 这个方法在创建对象时会自动被调用。它的主要任务就是完成对象的初始化工作,比如给对象的属性赋初始值。

    • self 参数: 这是 __init__ 以及所有实例方法第一个参数。它代表对象本身。当 cat1 = Cat("咪咪", 2) 被执行时,Python会自动把 cat1 这个对象传给 self。你可以把它理解为第一人称的“我”。
  • 实例方法 (Instance Method): 定义在类中的函数,它们是对象的“行为”。实例方法的第一个参数必须是 self,以便在方法内部可以访问和操作对象自身的属性。

class Cat:
    # 构造函数:当一只猫被创建时,这个方法会被自动调用
    def __init__(self, name, age):
        # self.name = name 的意思是:
        # “把传入的 name 参数的值,赋给‘我’(self)这个对象的 name 属性”
        print(f"一只叫 {name} 的小猫诞生了!")
        self.name = name
        self.age = age

    # 实例方法:定义猫的行为
    def meow(self):
        # 在方法内部,通过 self 访问自己的属性
        print(f"{self.name} 说:喵~ 我今年 {self.age} 岁了。")

# 实例化时,直接在类名后的括号里传入 __init__ 需要的参数 (除了 self)
cat1 = Cat("咪咪", 2)
cat2 = Cat("小黑", 3)

# 调用实例方法
cat1.meow() # 输出: 咪咪 说:喵~ 我今年 2 岁了。
cat2.meow() # 输出: 小黑 说:喵~ 我今年 3 岁了。

10.4 属性 (实例属性 vs 类属性)

对象的“数据”我们称之为属性。属性分为两种:

  • 实例属性 (Instance Attribute): 每个对象独有的属性。它们通常在 __init__ 方法中通过 self.attribute = value 的方式定义。比如,cat1name 是 "咪咪",cat2name 是 "小黑",它们互不影响。

  • 类属性 (Class Attribute): 所有对象共享的属性。它直接定义在类中,但在所有方法之外。类属性就像是写在“蓝图”上的公共信息。

class Cat:
    # 这是类属性,所有 Cat 的实例都共享这个属性
    species = "Felis catus" # 猫的学名

    def __init__(self, name, age):
        # 这些是实例属性,每只猫都不同
        self.name = name
        self.age = age

# 实例化
cat1 = Cat("咪咪", 2)
cat2 = Cat("小黑", 3)

# 访问实例属性
print(f"{cat1.name}的年龄是 {cat1.age}") # 输出: 咪咪的年龄是 2

# 访问类属性
# 可以通过类名访问
print(f"猫的科学名称是: {Cat.species}")
# 也可以通过实例访问
print(f"{cat1.name} 的物种是: {cat1.species}")

10.5 访问修饰符与封装 (公有、保护 _、私有 __)

封装 (Encapsulation) 是OOP的三大支柱之一。它的核心思想是:隐藏对象的内部实现细节,只对外暴露必要的接口

想象一下开车:你只需要操作方向盘、油门、刹车(接口),而不需要关心发动机内部的活塞如何运动(实现细节)。封装能保护数据不被随意修改,让代码更安全、更易于维护。

Python没有像Java或C++那样严格的 public, private 关键字,但它有一套命名约定来表示属性的可见性:

  • 公有 (Public): 默认情况下,所有属性和方法都是公有的。可以在任何地方被访问。
    self.name = name

  • 保护 (Protected): 以单下划线 _ 开头。这是一种约定,告诉其他程序员:“这是一个内部属性,不建议在类的外部直接访问,但如果你非要访问,我也拦不住你。”
    self._mood = "happy"

  • 私有 (Private): 以双下划线 __ 开头。这不仅仅是约定,Python会对其进行名称改写 (Name Mangling)。如果一个属性叫 __balance,在类的外部,你无法通过 object.__balance 访问它。Python会自动把它重命名为 _ClassName__balance。这提供了一种更强的保护机制。

经典案例:银行账户

class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner          # 公有属性
        self._account_type = "checking" # 保护属性
        self.__balance = balance    # 私有属性

    def deposit(self, amount):
        """存款 (公有方法,安全的接口)"""
        if amount > 0:
            self.__balance += amount
            print(f"成功存款 {amount} 元。")
        else:
            print("存款金额必须为正数!")

    def withdraw(self, amount):
        """取款 (公有方法,安全的接口)"""
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            print(f"成功取款 {amount} 元。")
        else:
            print("取款金额无效或余额不足!")

    def get_balance(self):
        """提供一个只读的接口来查看余额"""
        return self.__balance

# 创建一个账户对象
acc = BankAccount("张三", 1000)

# 尝试直接修改余额 (错误的做法!)
# acc.__balance -= 500 # 这会报错!AttributeError: 'BankAccount' object has no attribute '__balance'
# 因为 Python 已经把它改名为 _BankAccount__balance

# 正确的做法:通过我们提供的公有方法来操作
acc.deposit(500)
acc.withdraw(200)

# 通过安全的接口查看余额
current_balance = acc.get_balance()
print(f"{acc.owner} 的当前余额是: {current_balance} 元。")

恭喜你!你已经成功创造了你的第一个“物种”,并掌握了OOP的基石——类与对象。你学会了如何用 class 定义蓝图,用 __init__ 初始化对象,用 self 引用自身,并用封装来保护你的数据。

但这仅仅是OOP奇妙世界的开始。我们创造的“物种”目前还是孤立的。现实世界中,物种之间存在着“继承”关系(比如,“金毛”是“狗”的一种),也存在着“多态”现象(比如,猫和狗都会“叫”,但叫声不同)。

在下一章,我们将深入探索OOP的三大核心特性——继承、多态、抽象,你将学会如何构建复杂的“物种类族”,让你的代码世界变得更加生动和强大!准备好,迎接真正的“进化”吧!


-- 感谢阅读 --