Skip to content

07 面向对象编程

📋 资料说明

  • 来源:课程 day06 后半 ~ day07
  • 笔记尚硅谷大模型技术之Python1.0.docx 第 8 章"面向对象"
  • 代码day06/代码/P03_PP_OOP_FP.pyP04_Def_Class.py ~ P09_Other_Method.py
  • 视频:❌ 跳过(约 29 个视频:OOP 概念 → 类定义 → 封装 → 继承 → 多态 → 愤怒的小鸟案例)

🟢 🤖 AI 替代率:89%

为什么是这个水平:

类定义、继承语法、方法重写——这些是确定性语法,AI 近乎完美。但 OOP 的核心不是"怎么写",而是"为什么这样设计":

  • 封装:什么时候隐藏属性、什么时候暴露接口——需要判断
  • 继承 vs 组合:过深的继承树会带来维护噩梦,但"多深算深"需要经验
  • 多态:Python 的"鸭子类型"对刚从 Java 转来的人是个认知跃迁

这些设计决策是 AI 的薄弱环节。AI 可以写出符合语法规范的代码,但可能写出 5 层继承的"面条代码"。


👤 人工干预率:11% | 人类重点关注

为什么需要人工干预:

  1. 设计原则:单一职责(一个类只做一件事)、开闭原则(对扩展开放、对修改关闭)——这些需要人判断
  2. 继承 vs 组合:Python 支持多继承,但 MRO(方法解析顺序)容易混淆,过度使用继承应避免
  3. 鸭子类型:"看起来像鸭子、叫起来像鸭子,它就是鸭子"——Python 不检查类型,只检查方法

人类与 AI 协作建议:

  1. 让 AI 写出基础类结构,你来判断设计的合理性
  2. 重点关注:MRO 的执行顺序、区分 @classmethod / @staticmethod / 实例方法的使用场景
  3. 遇到"这个类该不该拆"的问题时,先问 AI 的建议,再结合业务场景判断

1. 面向对象基本概念

概念说明类比
类 (Class)对大量对象共性的抽象建筑设计图
对象 (Object)类的一个具体实例按图纸建造的房子
属性 (Attribute)对象有什么颜色、大小
方法 (Method)对象能做什么跑步、唱歌
python
# 万物皆对象:在 Python 中,整数、字符串、函数……都是对象
# 类是对大量对象共性的抽象
# 在程序中,类是创建对象的模板
# 类是客观事物在人脑中的主观反映

2. 类的定义与使用

python
class Person:
    """人的类"""
    # 类属性(所有实例共享)
    home = "Earth"
    
    def __init__(self, name="", age=0):
        # 实例属性(每个实例独享)
        self.name = name
        self.age = age
    
    # 实例方法
    def eat(self):
        print(f"{self.name} is eating")
    
    def drink(self):
        print(f"{self.name} is drinking")

# 类的操作 - 成员引用
print(Person.home)     # Earth(通过类名访问)
print(Person.__doc__)  # 人的类

# 类的操作 - 实例化
p1 = Person("Alice", 25)
p2 = Person("Bob", 30)

print(p1.name)  # Alice
print(p2.name)  # Bob
p1.eat()        # Alice is eating
p2.drink()      # Bob is drinking

3. 对象的创建过程

python
class Student:
    def __new__(cls, *args, **kwargs):
        """
        __new__ 才是真正的"构造方法"
        负责创建实例并分配内存
        大多数情况不需要重写
        """
        print("1. 创建实例")
        instance = super().__new__(cls)
        return instance
    
    def __init__(self, name, age):
        """
        __init__ 是"初始化方法"
        在 __new__ 创建实例后被调用
        给实例的属性赋值
        """
        print("2. 初始化实例")
        self.name = name
        self.age = age

s = Student("Alice", 25)
# 输出:
# 1. 创建实例
# 2. 初始化实例

self 的作用

python
class Dog:
    def __init__(self, name):
        self.name = name
    
    def bark(self):
        # self 就是调用这个方法的实例对象
        print(f"{self.name} says Wang!")

dog = Dog("旺财")
dog.bark()  # 等价于 Dog.bark(dog)

4. 类属性与实例属性

python
class Employee:
    # 类属性(所有实例共享)
    company = "ABC Corp"
    employee_count = 0
    
    def __init__(self, name, salary):
        # 实例属性(每个实例独享)
        self.name = name
        self.salary = salary
        Employee.employee_count += 1

e1 = Employee("Alice", 10000)
e2 = Employee("Bob", 12000)

print(e1.company)      # ABC Corp(从类继承)
print(e2.company)      # ABC Corp

# 修改类属性
Employee.company = "XYZ Corp"
print(e1.company)      # XYZ Corp(所有实例同步变)

# 通过实例修改类属性——实际上是创建了同名的实例属性
e1.company = "My Corp"  # 不是修改类属性!
print(e1.company)      # My Corp(实例属性)
print(e2.company)      # XYZ Corp(类属性没变)
print(Employee.company) # XYZ Corp(类属性没变)

5. 方法类型

python
class MyClass:
    # 实例方法:第一个参数是 self
    def instance_method(self):
        return f"实例方法,self={self}"
    
    # 类方法:第一个参数是 cls
    @classmethod
    def class_method(cls):
        return f"类方法,cls={cls}"
    
    # 静态方法:没有 self 或 cls
    @staticmethod
    def static_method():
        return "静态方法,无特殊参数"
    
    # 魔法方法
    def __str__(self):
        return "MyClass 的实例"
    
    def __len__(self):
        return 42

obj = MyClass()
print(obj.instance_method())  # 实例方法,self=<__main__.MyClass object>
print(MyClass.class_method()) # 类方法,cls=<class '__main__.MyClass'>
print(MyClass.static_method())# 静态方法,无特殊参数
print(obj)                    # MyClass 的实例(调用了 __str__)

6. 封装

封装:隐藏内部实现细节,只暴露必要的接口。

python
class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.__balance = balance  # 私有属性(双下划线)
    
    # 公开方法——对外接口
    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            return True
        return False
    
    def withdraw(self, amount):
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            return True
        return False
    
    def get_balance(self):
        return self.__balance
    
    # @property:把方法变成属性访问
    @property
    def balance(self):
        return self.__balance
    
    @balance.setter
    def balance(self, value):
        if value >= 0:
            self.__balance = value
        else:
            raise ValueError("余额不能为负数")

account = BankAccount("Alice", 1000)
account.deposit(500)
account.withdraw(200)
print(account.get_balance())  # 1300
# print(account.__balance)    # ❌ AttributeError(私有属性)
print(account.balance)        # 1300(property 访问)
account.balance = 2000        # setter

只读属性

python
class Student:
    def __init__(self, name, student_id):
        self.name = name
        self._student_id = student_id  # 单下划线表示"请当作私有"
    
    @property
    def student_id(self):
        """只读属性——没有 setter"""
        return self._student_id

s = Student("Alice", "S001")
print(s.student_id)  # S001
# s.student_id = "S002"  # ❌ AttributeError(没有 setter)

7. 继承

单继承

python
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        pass
    
    def move(self):
        print(f"{self.name} is moving")

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

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

dog = Dog("旺财")
cat = Cat("咪咪")
dog.move()   # 旺财 is moving(从 Animal 继承)
dog.speak()  # 旺财 says 汪汪!(自己实现)
cat.speak()  # 咪咪 says 喵喵!

多继承

python
class Flyable:
    def fly(self):
        print("Flying...")

class Swimmable:
    def swim(self):
        print("Swimming...")

class Duck(Flyable, Swimmable):
    def quack(self):
        print("Quack!")

duck = Duck()
duck.fly()    # Flying...
duck.swim()   # Swimming...
duck.quack()  # Quack!

MRO(方法解析顺序)

python
class A:
    def method(self):
        print("A")

class B(A):
    def method(self):
        print("B")

class C(A):
    def method(self):
        print("C")

class D(B, C):
    pass

d = D()
d.method()              # B(按 MRO 顺序查找)
print(D.__mro__)        # D → B → C → A → object
# Python 使用 C3 线性化算法确定 MRO

子类复用父类方法

python
class Animal:
    def __init__(self, name):
        self.name = name

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)  # 调用父类的 __init__
        self.breed = breed

dog = Dog("旺财", "金毛")
print(dog.name)   # 旺财
print(dog.breed)  # 金毛

8. 多态(Polymorphism)

Python 的"鸭子类型"——不关心对象的类型,只关心对象有没有该方法。

python
class Duck:
    def quack(self):
        print("鸭子呱呱叫")

class Person:
    def quack(self):
        print("人模仿鸭子叫")

def make_it_quack(thing):
    # Python 多态:不检查类型,直接调用方法
    thing.quack()

make_it_quack(Duck())    # 鸭子呱呱叫
make_it_quack(Person())  # 人模仿鸭子叫

# 只要实现了 __len__ 方法,就可以用 len()
class MyCollection:
    def __len__(self):
        return 100

print(len(MyCollection()))  # 100

练习题

练习 1:定义类

定义一个 Car 类,包含 start()stop() 方法,分别打印"启动"和"停止"。

练习 2:封装

定义一个 Temperature 类,有一个私有属性 _celsius,通过 property 暴露,并添加华氏度转换方法。

练习 3:继承

定义一个 Shape 基类和 Circle / Rectangle 子类,计算各自的面积。

练习 4:多态

定义三个不同的"通知器"(Email/SMS/WeChat),都实现 send(message) 方法,然后用一个函数统一调用。


参考答案

练习 1:

python
class Car:
    def __init__(self, brand):
        self.brand = brand
    
    def start(self):
        print(f"{self.brand} 启动")
    
    def stop(self):
        print(f"{self.brand} 停止")

练习 2:

python
class Temperature:
    def __init__(self, celsius=0):
        self._celsius = celsius
    
    @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

练习 3:

python
import math

class Shape:
    def area(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return math.pi * self.radius ** 2

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height

练习 4:

python
class EmailNotifier:
    def send(self, message):
        print(f"[Email] {message}")

class SMSNotifier:
    def send(self, message):
        print(f"[SMS] {message}")

class WeChatNotifier:
    def send(self, message):
        print(f"[WeChat] {message}")

def notify(notifier, message):
    notifier.send(message)

notify(EmailNotifier(), "Hello")  # [Email] Hello
notify(SMSNotifier(), "Hello")    # [SMS] Hello

OPC 超级个体实战指南