说明:本文兼顾有C++/Java背景的程序员和零基础小白,用最通俗的语言配合详细的代码和运行结果,帮助你彻底理解面向对象编程。


第一章:为什么要学面向对象?

1.1 故事版解释:什么是"对象"?

想象一下,你在玩一款游戏,比如《王者荣耀》或者《原神》。

游戏里面有很多"英雄"或者"角色",每个角色都有:

  • 属性(数据):比如生命值、攻击力、防御力、等级、装备
  • 技能(行为/方法):比如普通攻击、必杀技、闪现、治疗

在面向对象编程(OOP)里,我们把每一个游戏角色看作一个对象(Object)

通俗理解:对象就像是一个"东西",它有自己的"特征"(属性)和"能力"(方法)。

1.2 对比:过程式 vs 面向对象

让我用一个具体的例子来说明两者的区别。

场景:计算圆的面积

过程式写法(像C语言那样):

# 这就是过程式编程:数据和函数是分开的

# 第1步:定义数据
radius = 5          # 圆的半径
pi = 3.14159        # 圆周率

# 第2步:定义函数(操作数据)
def calculate_circle_area(r):
    """计算圆的面积"""
    return pi * r * r

# 第3步:调用函数
area = calculate_circle_area(radius)
print("圆的面积是:", area)

运行结果:

圆的面积是: 78.53975

面向对象写法:

# 面向对象:把数据和操作封装在一起

class Circle:
    """这是一个"圆"类"""
    
    # 初始化方法,创建对象时会自动调用
    def __init__(self, radius):
        # self.radius 是对象的属性(特征)
        self.radius = radius
        self.pi = 3.14159
    
    # 这是对象的方法(能力)
    def calculate_area(self):
        """计算圆的面积"""
        return self.pi * self.radius * self.radius

# 创建(实例化)一个Circle对象
my_circle = Circle(5)  # 创建一个半径为5的圆

# 调用对象的方法
area = my_circle.calculate_area()
print("圆的面积是:", area)

运行结果:

圆的面积是: 78.53975

两种写法有什么区别?

对比项 过程式 面向对象
数据在哪里? 分散的变量 封装在对象里
函数在哪里? 独立的函数 对象的方法
好处 简单直接 更好管理、更像现实世界

通俗比喻:

  • 过程式就像去菜市场买菜,老板把白菜、土豆、萝卜分别放在不同的摊位上,你得自己去取
  • 面向对象就像去超市买菜,已经被分类包装好了,你需要什么直接拿对应的袋子

第二章:Python类和对象基础

2.1 什么是类(Class)?

就像是一个"模板"或者"模具"。

举例说明:

  • = "人类"的概念(抽象的)
  • 对象 = 张三、李四、王五(具体的实例)

一句话理解:类定义了一个"种类"的事物有什么特征和行为,但类本身不是具体的东西。具体的东西叫做"对象"或"实例"。

2.2 第一个类:学生类

让我们从一个最简单的例子开始:

# 定义一个"学生"类
class Student:
    """这是一个学生类"""
    
    # __init__ 是初始化方法,创建对象时自动调用
    # self 代表创建出来的那个对象本身
    def __init__(self, name, age):
        # 给对象添加属性(特征)
        self.name = name    # 学生姓名
        self.age = age      # 学生年龄
    
    # 定义一个方法(行为)
    def introduce(self):
        """自我介绍"""
        print(f"大家好,我叫{self.name},今年{self.age}岁")

# ========== 这里是使用类的代码 ==========

# 创建(实例化)一个学生对象
student1 = Student("张三", 18)
student2 = Student("李四", 19)

# 调用对象的方法
student1.introduce()
student2.introduce()

运行结果:

大家好,我叫张三,今年18岁
大家好,我叫李四,今年19岁

代码解释

第1行:class Student:

  • class 是Python的关键字,表示要定义一个类
  • Student 是类的名字(可以自己取,一般首字母大写)

**第2行:"""这是一个学生类"""

  • 这是类的文档字符串,说明这个类是干什么的

第4-6行:def __init__(self, name, age):

  • __init__ 是"初始化方法"的特殊名字
  • 当我们创建对象时(比如 Student("张三", 18)),这个方法会自动被调用
  • self 是必须的参数,它代表"这个对象本身"
  • nameage 是创建对象时传入的参数

第8-9行:self.name = name

  • 把传入的 name 赋值给对象的 name 属性
  • self.name 中的 self. 表示"这个对象的"

第12-13行:定义 introduce 方法

  • 方法就是"函数",但它是属于对象的
  • 方法的第一个参数必须是 self

第18-19行:创建对象

  • Student("张三", 18) 这行代码会:
    1. 调用 __init__ 方法
    2. 创建一个新的对象
    3. 把 “张三” 传给 name 参数,18 传给 age 参数
    4. 返回这个对象

2.3 self 到底是什么?

self 是初学者最容易困惑的地方。让我详细解释:

class Dog:
    """狗类"""
    
    def __init__(self, name, breed):
        # self 就是正在创建的这个对象
        # self.name 给这个对象添加了一个叫 name 的属性
        self.name = name
        self.breed = breed
    
    def bark(self):
        # 在方法内部使用 self.name,表示"这个对象的 name 属性"
        print(f"{self.name} 汪汪叫!")

# ========== 测试 ==========

# 创建两个狗对象
dog1 = Dog("旺财", "土狗")
dog2 = Dog("小白", "萨摩耶")

# 调用方法
dog1.bark()
dog2.bark()

运行结果:

旺财 汪汪叫!
小白 汪汪叫!

self 的本质

想象一下,当你调用 dog1.bark() 时,Python 内部其实是这样执行的:

# 这只是 Python 内部的原理,实际不需要这样写
Dog.bark(dog1)  # 把 dog1 对象传给 bark 方法

所以:

  • self 就是"当前调用这个方法的那个对象"
  • self.name 就是"当前对象的 name 属性"

第三章:属性和方法的深入理解

3.1 对象的属性(数据)

属性就是对象保存的数据。每个对象都可以有自己的属性。

class Person:
    """人类"""
    
    def __init__(self, name, age, gender):
        # 这些都是实例属性:每个对象独立的属性
        self.name = name         # 姓名
        self.age = age           # 年龄
        self.gender = gender     # 性别
        self.height = 170        # 身高(有默认值)
        self.weight = 65         # 体重(有默认值)
    
    def show_info(self):
        """显示个人信息"""
        print("=" * 30)
        print(f"姓名: {self.name}")
        print(f"年龄: {self.age} 岁")
        print(f"性别: {self.gender}")
        print(f"身高: {self.height} cm")
        print(f"体重: {self.weight} kg")
        print("=" * 30)

# ========== 使用 ==========

# 创建两个person对象
p1 = Person("小明", 25, "男")
p2 = Person("小红", 22, "女")

# 修改 p1 的属性
p1.age = 26           # 过了生日,长大一岁
p1.height = 175       # 长高了

# 修改 p2 的属性
p2.weight = 55        # 减肥了

# 显示信息
p1.show_info()
p2.show_info()

运行结果:

==============================
姓名: 小明
年龄: 26 岁
性别: 男
身高: 175 cm
体重: 65 kg
==============================
==============================
姓名: 小红
年龄: 22 岁
性别: 女
身高: 170 cm
体重: 55 kg
==============================

重要说明:每个对象是独立的

class Dog:
    def __init__(self, name):
        self.name = name

# 创建两个狗
dog1 = Dog("旺财")
dog2 = Dog("小白")

# 修改 dog1 的名字
dog1.name = "大黄"

# 验证:dog1 和 dog2 是独立的
print(f"dog1.name = {dog1.name}")   # 变成了 "大黄"
print(f"dog2.name = {dog2.name}")   # 还是 "小白"

运行结果:

dog1.name = 大黄
dog2.name = 小白

3.2 对象的方法(行为)

方法是对象可以执行的操作。

普通方法:最常见

class Calculator:
    """计算器类"""
    
    def __init__(self):
        # 结果会保存这个属性里
        self.result = 0
    
    def add(self, x, y):
        """加法"""
        self.result = x + y
        return self.result
    
    def subtract(self, x, y):
        """减法"""
        self.result = x - y
        return self.result
    
    def show_result(self):
        """显示结果"""
        print(f"计算结果是: {self.result}")

# ========== 使用 ==========

calc = Calculator()

# 调用加法
r = calc.add(10, 5)
print(f"10 + 5 = {r}")

# 调用减法
calc.subtract(20, 8)
calc.show_result()

运行结果:

10 + 5 = 15
计算结果是: 12

类变量 vs 实例变量

这是另一个容易混淆的概念:

class Student:
    # 这是类变量:在类里面直接定义的变量
    school_name = "阳光中学"      # 所有学生都在这个学校
    total_students = 0          # 学生总数
    
    def __init__(self, name, age):
        # 这是实例变量:在__init__里,用self.定义的变量
        self.name = name         # 每个学生有自己的名字
        self.age = age           # 每个学生有自己的年龄
        
        # 修改类变量(学生数量+1)
        Student.total_students += 1
    
    def show_info(self):
        """显示学生信息"""
        print(f"{self.name}{self.age}岁,就读于{self.school_name}")

# ========== 使用 ==========

# 创建学生对象
s1 = Student("张三", 15)
s2 = Student("李四", 16)
s3 = Student("王五", 15)

# 查看类变量
print(f"学校名称: {Student.school_name}")
print(f"学生总数: {Student.total_students}")

# 显示学生信息
s1.show_info()
s2.show_info()

运行结果:

学校名称: 阳光中学
学生总数: 3
张三,15岁,就读于阳光中学
李四,16岁,就读于阳光中学
王五,15岁,就读于阳光中学

类变量和实例变量的区别

特性 类变量 实例变量
定义位置 类里面,直接定义 __init__ 方法里,用 self.
归属 类本身 各个对象
共享 所有对象共享一份 每个对象独立一份
访问方式 类名.变量名对象.变量名 只能通过 对象.变量名

第四章:面向对象的三大特性

面向对象有三大特性:封装继承多态。这是OOP的核心!

4.1 封装:把东西包装起来

封装就是把数据和操作封装在一起,隐藏内部细节,只暴露必要的接口。

为什么需要封装?

举例:你每天开车,不需要知道发动机是怎么工作的,只需要知道:

  • 踩油门车会前进
  • 踩刹车车会停下
  • 方向盘控制方向

这就是"封装"的思想:把复杂的内部细节隐藏起来,只提供简单的接口。

Python中如何实现封装?

Python用"私有属性"来实现封装:

class BankAccount:
    """银行账户类"""
    
    def __init__(self, owner, balance):
        # self.__balance 中的 __ 表示"私有"
        # Python 会把它变成 _BankAccount__balance
        # 外部不能直接访问
        self.owner = owner
        self.__balance = balance      # 私有属性:余额
        self.__password = "123456"    # 私有属性:密码
    
    def deposit(self, amount):
        """存款:公共方法,外部可以调用"""
        if amount > 0:
            self.__balance += amount
            print(f"存款成功!当前余额: {self.__balance}")
        else:
            print("存款金额必须大于0")
    
    def withdraw(self, amount):
        """取款"""
        if amount > self.__balance:
            print("余额不足!")
        elif amount > 0:
            self.__balance -= amount
            print(f"取款成功!当前余额: {self.__balance}")
        else:
            print("取款金额必须大于0")
    
    def get_balance(self):
        """查看余额(受保护的方法)"""
        return self.__balance

# ========== 使用 ==========

# 创建账户
account = BankAccount("张三", 1000)

# 正常的操作:通过公共方法
account.deposit(500)     # 存款
account.withdraw(200)   # 取款

# 查看余额
print(f"余额: {account.get_balance()}")

# 尝试直接访问私有属性(会报错)
print(f"尝试直接访问: {account.__balance}")

运行结果:

存款成功!当前余额: 1500
取款成功!当前余额: 1300
余额: 1300
Traceback (most recent call last):
  File "xxx", line xxx, in <module>
    print(f"尝试直接访问: {account.__balance}")
AttributeError: 'BankAccount' object has no attribute '__balance'

封装的优点

  1. 保护数据:防止外部随意修改重要数据
  2. 简化接口:用户只需要调用简单的方法
  3. 便于维护:内部实现可以随时改变,不影响外部

4.2 继承:像遗传一样

继承就是"子类"继承"父类"的属性和方法。

生活中的继承例子

  • 儿子继承父亲的财产
  • 狗继承"动物"的特性
  • 汽车继承"交通工具"的特性

Python中如何实现继承?

# ========== 第1步:定义父类(基类)==========
class Animal:
    """动物类:父类/基类"""
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def eat(self):
        """吃东西"""
        print(f"{self.name} 正在吃东西")
    
    def sleep(self):
        """睡觉"""
        print(f"{self.name} 正在睡觉")
    
    def speak(self):
        """发出声音(父类不知道具体什么声音)"""
        print(f"{self.name} 发出了声音")

# ========== 第2步:定义子类(继承父类)==========
class Dog(Animal):
    """狗类:继承自动物类"""
    
    def __init__(self, name, age, breed):
        # 调用父类的 __init__ 方法
        super().__init__(name, age)
        self.breed = breed  # 狗特有的属性:品种
    
    # 重写父类的方法
    def speak(self):
        """重写发出声音的方法"""
        print(f"{self.name} 汪汪叫!")
    
    # 狗特有的方法
    def fetch_ball(self):
        """捡球"""
        print(f"{self.name} 跑去捡球了!")

class Cat(Animal):
    """猫类:继承自动物类"""
    
    def __init__(self, name, age, color):
        super().__init__(name, age)
        self.color = color  # 猫特有的属性:颜色
    
    # 重写父类的方法
    def speak(self):
        """重写发出声音的方法"""
        print(f"{self.name} 喵喵叫!")
    
    # 猫特有的方法
    def climb_tree(self):
        """爬树"""
        print(f"{self.name} 爬到树上去了!")

# ========== 使用 ==========

print("=== 创建动物 ===")
animal = Animal("小动物", 1)
animal.eat()
animal.sleep()
animal.speak()

print("\n=== 创建狗 ===")
dog = Dog("旺财", 3, "土狗")
dog.eat()           # 继承自父类的方法
dog.sleep()         # 继承自父类的方法
dog.speak()         # 重写后的方法
dog.fetch_ball()    # 狗特有的方法

print("\n=== 创建猫 ===")
cat = Cat("咪咪", 2, "橘色")
cat.eat()           # 继承自父类
cat.speak()         # 重写后的方法
cat.climb_tree()    # 猫特有的方法

运行结果:

=== 创建动物 ===
小动物 正在吃东西
小动物 正在睡觉
小动物 发出了声音

=== 创建狗 ===
旺财 正在吃东西
旺财 正在睡觉
旺财 汪汪叫!
旺财 跑去捡球了!

=== 创建猫 ===
咪咪 正在吃东西
咪咪 喵喵叫!
咪咪 爬到树上去了!

继承的概念图

        Animal (动物类 - 父类)
       /        |        \
      /         |         \
   Dog       Cat       ...   (子类)
   (狗)      (猫)

继承的核心要点

  1. 子类自动拥有父类的所有属性和方法
  2. 子类可以添加自己特有的属性和方法
  3. 子类可以"重写"(override)父类的方法
  4. 使用 super().__init__() 调用父类的方法

4.3 多态:同一个方法,不同的表现

多态就是"同一个方法调用,不同对象有不同表现"。

生活中的多态例子

  • "叫"这个动作:
    • 人叫:“你好!”
    • 狗叫:“汪汪!”
    • 猫叫:“喵喵!”
    • 鸭子叫:“嘎嘎!”

虽然都是"叫",但不同动物发出的声音不同,这就是多态。

Python中的多态

class Animal:
    """动物基类"""
    
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        """动物的叫声"""
        print(f"{self.name} 发出了声音")

class Dog(Animal):
    def speak(self):
        print(f"{self.name} 汪汪叫!")

class Cat(Animal):
    def speak(self):
        print(f"{self.name} 喵喵叫!")

class Duck(Animal):
    def speak(self):
        print(f"{self.name} 嘎嘎叫!")

# ========== 多态的威力 ==========

def make_speak(animal):
    """让动物发出声音"""
    # 不管传入什么动物,都能正确调用它的 speak 方法
    animal.speak()

# 创建各种动物
dog = Dog("旺财")
cat = Cat("咪咪")
duck = Duck("唐老鸭")

# 调用同一个函数,不同对象表现不同
print("=== 多态演示 ===")
make_speak(dog)     # 传入狗 -> 汪汪叫
make_speak(cat)     # 传入猫 -> 喵喵叫
make_speak(duck)    # 传入鸭子 -> 嘎嘎叫

运行结果:

=== 多态演示 ===
旺财 汪汪叫!
咪咪 喵喵叫!
唐老鸭 嘎嘎叫!

多态的好处

  1. 代码简洁:同一个函数可以处理不同类型的对象
  2. 易于扩展:添加新动物不需要修改 make_speak 函数
  3. 符合开闭原则:对扩展开放,对修改封闭

第五章:高级特性

5.1 @property:像访问属性一样调用方法

有时候,我们不想让外部直接访问某个属性,但又要提供一个"查看"的方式。这时可以用 @property

class Temperature:
    """温度类"""
    
    def __init__(self, celsius):
        self._celsius = celsius   # 用 _ 表示"受保护的"
    
    # @property 使方法可以像属性一样访问
    @property
    def celsius(self):
        """获取摄氏度"""
        return self._celsius
    
    @celsius.setter
    def celsius(self, value):
        """设置摄氏度(带验证)"""
        if value < -273.15:
            raise ValueError("温度不能低于绝对零度!")
        self._celsius = value
    
    @property
    def fahrenheit(self):
        """获取华氏度(只能读取,不能设置)"""
        return self._celsius * 9/5 + 32

# ========== 使用 ==========

temp = Temperature(25)

# 像访问属性一样调用方法(不用写括号)
print(f"当前温度: {temp.celsius}°C")
print(f"华氏温度: {temp.fahrenheit}°F")

# 设置温度
temp.celsius = 30
print(f"修改后: {temp.celsius}°C")

# 设置无效温度(会报错)
try:
    temp.celsius = -300
except ValueError as e:
    print(f"错误: {e}")

运行结果:

当前温度: 25°C
华氏温度: 77.0°F
修改后: 30°C
错误: 温度不能低于绝对零度!

5.2 魔术方法:让对象支持内置操作

Python有很多以双下划线开头和结尾的方法,叫做"魔术方法"。它们让对象可以支持Python的内置操作。

strrepr:对象的字符串表示

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    # str() 或 print() 时调用
    def __str__(self):
        return f"Person({self.name}, {self.name})"
    
    # 直接输入对象名时调用(调试用)
    def __repr__(self):
        return f"Person(name='{self.name}', age={self.age})"

# ========== 使用 ==========

p = Person("张三", 25)

print(str(p))       # 使用 __str__
print(repr(p))      # 使用 __repr__
print(p)            # 默认调用 __str__

运行结果:

Person(张三, 张三)
Person(name='张三', age=25)
Person(张三, 张三)

运算符重载:让对象支持数学运算

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 __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)
    
    # 字符串表示
    def __str__(self):
        return f"Vector({self.x}, {self.y})"

# ========== 使用 ==========

v1 = Vector(1, 2)
v2 = Vector(3, 4)

# 直接用 + 号相加
v3 = v1 + v2
v4 = v1 - v2

print(f"v1 = {v1}")
print(f"v2 = {v2}")
print(f"v1 + v2 = {v3}")
print(f"v1 - v2 = {v4}")

运行结果:

v1 = Vector(1, 2)
v2 = Vector(3, 4)
v1 + v2 = Vector(4, 6)
v1 - v2 = Vector(-2, -2)

5.3 类方法 vs 静态方法

Python中有三种方法:实例方法、类方法、静态方法。

class MathTools:
    """数学工具类"""
    
    # 实例方法:第一个参数是 self
    def power(self, base, exponent):
        """实例方法:计算幂"""
        return base ** exponent
    
    # 类方法:第一个参数是 cls(类本身)
    @classmethod
    def circle_area(cls, radius):
        """类方法:计算圆面积"""
        return 3.14159 * radius ** 2
    
    # 静态方法:没有 self 或 cls
    @staticmethod
    def max_value(a, b):
        """静态方法:返回最大值"""
        return a if a > b else b

# ========== 使用 ==========

# 实例方法:需要创建对象
obj = MathTools()
print(f"2的10次方: {obj.power(2, 10)}")

# 类方法:直接用类名调用,不需要创建对象
print(f"半径为5的圆面积: {MathTools.circle_area(5)}")

# 静态方法:也可以用类名直接调用
print(f"最大值: {MathTools.max_value(10, 20)}")
print(f"最大值: {obj.max_value(10, 20)}")  # 用对象调用也可以

运行结果:

2的10次方: 1024
半径为5的圆面积: 78.53975
最大值: 20
最大值: 20

三种方法的区别

类型 第一个参数 调用方式 适用场景
实例方法 self 对象.方法() 操作实例数据
类方法 cls 类名.方法() 操作类数据
静态方法 类名.方法() 工具函数

第六章:综合实战

6.1 完整的例子:学生管理系统

让我们用面向对象的方式,实现一个简单的学生管理系统:

class Student:
    """学生类"""
    
    def __init__(self, student_id, name, age, gender):
        self.student_id = student_id
        self.name = name
        self.age = age
        self.gender = gender
        self.scores = {}  # 科目:分数
    
    def add_score(self, subject, score):
        """添加成绩"""
        if 0 <= score <= 100:
            self.scores[subject] = score
            print(f"✓ 已添加 {self.name}{subject} 成绩: {score}")
        else:
            print(f"✗ 成绩必须在0-100之间!")
    
    def get_average(self):
        """获取平均分"""
        if not self.scores:
            return 0
        return sum(self.scores.values()) / len(self.scores)
    
    def show_info(self):
        """显示学生信息"""
        print(f"\n{'='*40}")
        print(f"学号: {self.student_id}")
        print(f"姓名: {self.name}")
        print(f"年龄: {self.age}")
        print(f"性别: {self.gender}")
        print("-" * 40)
        print("成绩:")
        if self.scores:
            for subject, score in self.scores.items():
                print(f"  {subject}: {score}")
            print(f"平均分: {self.get_average():.2f}")
        else:
            print("  暂无成绩")
        print(f"{'='*40}\n")


class StudentManager:
    """学生管理系统"""
    
    def __init__(self):
        self.students = {}  # 学号: 学生对象
    
    def add_student(self, student):
        """添加学生"""
        if student.student_id in self.students:
            print(f"✗ 学号 {student.student_id} 已存在!")
        else:
            self.students[student.student_id] = student
            print(f"✓ 添加学生成功: {student.name}")
    
    def find_student(self, student_id):
        """查找学生"""
        return self.students.get(student_id)
    
    def show_all(self):
        """显示所有学生"""
        print("\n" + "="*50)
        print(f"共有 {len(self.students)} 名学生")
        print("="*50)
        for student in self.students.values():
            student.show_info()
    
    def get_top_student(self):
        """获取成绩最高的学生"""
        if not self.students:
            return None
        
        top_student = None
        top_avg = -1
        
        for student in self.students.values():
            avg = student.get_average()
            if avg > top_avg:
                top_avg = avg
                top_student = student
        
        return top_student


# ========== 使用示例 ==========

print("=== 创建学生管理系统 ===")
manager = StudentManager()

# 创建学生
print("\n--- 添加学生 ---")
s1 = Student("001", "张三", 18, "男")
s2 = Student("002", "李四", 17, "女")
s3 = Student("003", "王五", 18, "男")

# 添加成绩
s1.add_score("数学", 85)
s1.add_score("语文", 90)
s1.add_score("英语", 88)

s2.add_score("数学", 92)
s2.add_score("语文", 78)
s2.add_score("英语", 95)

s3.add_score("数学", 70)
s3.add_score("语文", 85)
s3.add_score("英语", 80)

# 添加到管理系统
manager.add_student(s1)
manager.add_student(s2)
manager.add_student(s3)

# 显示所有学生
manager.show_all()

# 查找学生
print("\n--- 查找学生 ---")
student = manager.find_student("002")
if student:
    student.show_info()

# 显示最高分学生
print("\n--- 成绩最高的学生 ---")
top = manager.get_top_student()
if top:
    print(f"成绩最高的学生是: {top.name},平均分: {top.get_average():.2f}")

运行结果:

=== 创建学生管理系统 ===

--- 添加学生 ---
✓ 已添加 张三 的 数学 成绩: 85
✓ 已添加 张三 的 语文 成绩: 90
✓ 已添加 张三 的 英语 成绩: 88
✓ 已添加 张三 的 历史 成绩: 95
✓ 已添加 李四 的 数学 成绩: 92
✓ 已添加 李四 的 语文 成绩: 78
✓ 已添加 李四 的 英语 成绩: 95
✓ 已添加 王五 的 数学 成绩: 70
✓ 已添加 王五 的 语文 成绩: 85
✓ 已添加 王五 的 英语 成绩: 80
✓ 添加学生成功: 张三
✓ 添加学生成功: 李四
✓ 添加学生成功: 王五

==================================================
共有 3 名学生
==================================================

========================================
学号: 001
姓名: 张三
年龄: 18
性别: 男
----------------------------------------
成绩:
  数学: 85
  语文: 90
  英语: 88
  历史: 95
平均分: 89.50
========================================

========================================
学号: 002
姓名: 李四
年龄: 17
性别: 女
----------------------------------------
成绩:
  数学: 92
  语文: 78
  英语: 95
平均分: 88.33
========================================

========================================
学号: 003
姓名: 王五
年龄: 18
性别: 男
----------------------------------------
成绩:
  数学: 70
  语文: 85
  英语: 80
平均分: 78.33
========================================


--- 查找学生 ---

========================================
学号: 002
姓名: 李四
年龄: 17
性别: 女
----------------------------------------
成绩:
  数学: 92
  语文: 78
  英语: 95
平均分: 88.33
========================================


--- 成绩最高的学生 ---
成绩最高的学生是: 张三,平均分: 89.50

第七章:常见问题和解答

Q1: 什么时候用面向对象?

简单原则:

  • 如果只是简单的数据处理,函数就够了
  • 如果有相关联的数据和行为,或者需要模拟现实世界的事物,用面向对象

Q2: 类变量和实例变量怎么选?

  • 如果数据应该被所有对象共享,用类变量(如学校名字)
  • 如果数据是每个对象特有的,用实例变量(如学生姓名)

Q3: 继承好还是组合好?

  • 继承:"是"的关系(Dog Animal)
  • 组合:"有"的关系(Car Engine)

优先使用组合,因为继承的耦合度太高。

Q4: 私有属性真的安全吗?

Python的私有属性只是"约定",不是真正的安全。可以用 _ClassName__attr 访问。但这是"不推荐"的做法。


总结

面向对象的三大核心概念

概念 通俗理解 关键词
封装 把数据和操作包装在一起 隐藏细节、保护数据
继承 子类拥有父类的特性 代码复用、扩展
多态 同一方法,不同表现 灵活、扩展性强

Python面向对象常用语法

# 定义类
class 类名:
    def __init__(self, 参数):
        self.属性 = 参数
    
    def 方法(self, 参数):
        # 方法代码

# 创建对象
对象 = 类名(参数)

# 调用方法
对象.方法(参数)

# 继承
class 子类(父类):
    def __init__(self, 参数):
        super().__init__(参数)  # 调用父类
        # 子类特有属性
    
    def 方法(self):  # 重写父类方法
        # 新实现

学习面向对象是一个循序渐进的过程。建议:

  1. 先理解概念(封装、继承、多态)
  2. 多写代码练习
  3. 阅读优秀的开源代码
  4. 在实际项目中应用

掌握了面向对象编程,你就掌握了现代软件开发的核心思维。加油!💪

更多推荐