今日目标:理解 OOP 思想,掌握类与对象、封装、继承、多态,完成愤怒的小鸟案例设计


一、面向过程 vs 面向对象

面向过程 面向对象(OOP)
步骤组织代码 对象组织代码
函数是核心 是核心
适合简单任务 适合复杂系统

面向对象三大特性封装继承多态

类比

  • 面向过程:做菜的步骤(洗菜→切菜→炒菜)
  • 面向对象:做菜的角色(厨师、锅、食材),每个角色有自己的属性和行为

二、类与对象

2.1 基本概念

  • 类(Class):对象的模板/蓝图(如"汽车设计图")
  • 对象(Object):类的实例(如"一辆具体的红色 Tesla")

2.2 定义类与创建对象

class Student:
    """学生类"""

    def __init__(self, name, age):
        """构造方法,创建对象时自动调用"""
        self.name = name    # 实例属性
        self.age = age

    def introduce(self):
        """实例方法"""
        print(f"我是{self.name},{self.age}岁")

# 创建对象(实例化)
s1 = Student("张三", 20)
s2 = Student("李四", 22)

s1.introduce()  # 我是张三,20岁
s2.introduce()  # 我是李四,22岁

2.3 self 是什么?

self 代表当前对象本身。调用方法时 Python 自动把对象传给 self。

s1.introduce()  # 等价于 Student.introduce(s1)

2.4 init 构造方法

创建对象时自动调用,用于初始化属性。

2.5 类属性 vs 实例属性

class Dog:
    species = "犬科"       # 类属性,所有实例共享

    def __init__(self, name):
        self.name = name   # 实例属性,每个对象独有

d1 = Dog("旺财")
d2 = Dog("来福")
print(d1.species, d2.species)  # 犬科 犬科
print(d1.name, d2.name)        # 旺财 来福

2.6 三种方法

类型 第一个参数 调用方式 用途
实例方法 self 对象.方法() 操作实例属性
类方法 cls 类.方法() 操作类属性
静态方法 类.方法() 与类相关但不访问属性
class MyClass:
    count = 0

    def instance_method(self):
        print("实例方法")

    @classmethod
    def class_method(cls):
        cls.count += 1

    @staticmethod
    def static_method():
        print("静态方法")

2.7 动态添加属性和方法

s = Student("王五", 21)
s.score = 90          # 动态添加属性
print(s.score)

三、封装

封装 = 把数据和对数据的操作包装在一起,隐藏内部细节。

3.1 访问控制约定

前缀 含义 实际效果
公开 可任意访问
_name 受保护(约定) 仍可访问,但不建议
__name 私有(名称改写) 外部不可直接访问
class BankAccount:
    def __init__(self, balance):
        self.__balance = balance

    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount

    def get_balance(self):
        return self.__balance

acc = BankAccount(1000)
acc.deposit(500)
print(acc.get_balance())  # 1500
# print(acc.__balance)      # AttributeError

3.2 property 装饰器

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value <= 0:
            raise ValueError("半径必须为正")
        self._radius = value

    @property
    def area(self):
        return 3.14159 * self._radius ** 2

c = Circle(5)
print(c.area)    # 78.54
c.radius = 10    # 通过 setter 修改

四、继承

继承 = 子类自动获得父类的属性和方法。

4.1 单继承

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}:喵喵喵")

dog = Dog("旺财")
dog.speak()  # 旺财:汪汪汪

4.2 super() 调用父类

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Student(Person):
    def __init__(self, name, age, school):
        super().__init__(name, age)
        self.school = school

s = Student("张三", 20, "清华大学")
print(s.name, s.school)

4.3 多继承(了解)

class A:
    def func(self): print("A")
class B:
    def func(self): print("B")
class C(A, B):
    pass

c = C()
c.func()  # A(按 MRO 顺序查找)

五、多态

多态 = 同一方法调用,不同类有不同表现

def make_sound(animal):
    animal.speak()  # 不关心具体是什么动物

make_sound(Dog("旺财"))   # 汪汪汪
make_sound(Cat("咪咪"))   # 喵喵喵

好处:新增子类无需修改调用方代码。


六、案例:愤怒的小鸟(设计思路)

6.1 游戏背景

弹弓发射小鸟,击倒障碍物上的猪。

6.2 类设计

Bird(父类)
 ├── RedBird(红鸟:普通)
 ├── YellowBird(黄鸟:加速冲刺)
 └── BlueBird(蓝鸟:分裂为三只)

Obstacle(障碍物)
Pig(猪)
Slingshot(弹弓)
Game(游戏主控)

6.3 核心代码框架

class Bird:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def fly(self):
        print(f"鸟从({self.x},{self.y})飞出")

class RedBird(Bird):
    def fly(self):
        print(f"红鸟直线飞行")

class YellowBird(Bird):
    def fly(self):
        print(f"黄鸟加速冲刺!")

class Pig:
    def __init__(self, hp):
        self.hp = hp

    def hit(self, damage):
        self.hp -= damage
        if self.hp <= 0:
            print("猪被击倒!")

def launch(bird):
    bird.fly()  # 多态

launch(RedBird(0, 0))
launch(YellowBird(10, 5))

七、练习题

基础题

1. 定义 Rectangle 类,属性 width/height,方法 area() 和 perimeter()。

2. 定义 Book 类,用 property 实现 price 的 getter/setter,价格不能为负。

3. 定义 Vehicle 父类和 CarBike 子类,子类重写 move()。

4. 用多态:定义 Shape 父类和 CircleRectangle 子类,统一调用 area()。

进阶题

5. 设计 Employee 父类和 Manager 子类,Manager 的 get_salary() 含 20% 奖金。

6. 实现 Stack(栈)类:push、pop、peek、is_empty。

参考答案

点击展开参考答案

class Rectangle:
    def __init__(self, w, h):
        self.width, self.height = w, h
    def area(self): return self.width * self.height
    def perimeter(self): return 2 * (self.width + self.height)

class Book:
    def __init__(self, title, price):
        self.title = title
        self._price = price
    @property
    def price(self): return self._price
    @price.setter
    def price(self, v):
        if v < 0: raise ValueError("价格不能为负")
        self._price = v

class Shape:
    def area(self): raise NotImplementedError
class Circle(Shape):
    def __init__(self, r): self.r = r
    def area(self): return 3.14 * self.r ** 2

class Stack:
    def __init__(self): self._data = []
    def push(self, item): self._data.append(item)
    def pop(self): return self._data.pop() if self._data else None
    def peek(self): return self._data[-1] if self._data else None
    def is_empty(self): return len(self._data) == 0
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐