第6章 面向对象

类与对象、属性与方法、继承与多态、魔术方法与 dataclass。

OOP第9-10周3 讲6 段示例代码

本章学习目标

  • 能定义类、创建对象、访问属性与调用方法
  • 理解 __init__ 与 self 的作用
  • 能用继承复用代码并重写方法
  • 能用 __str__/__repr__ 与 dataclass 简化代码

本章导览

核心内容

6.1

类与对象

类是模板,对象是实例;__init__ 负责初始化,self 指向当前对象。

能定义类并创建对象能区分实例属性与类属性能用方法封装行为

知识点

定义与实例化

  • class Student: 缩进写 __init__(self, ...) 与各种方法。
  • s = Student("张三", 20) 会调用 __init__。
  • self 是第一个参数,代表“这个对象自己”,调用时不用传。

实例属性与类属性

  • self.name = name 写在 __init__ 里 → 每个对象一份。
  • 类里直接写 school = "一中" → 所有对象共享。
  • 改实例属性只影响自己;改类属性会影响所有没覆盖它的对象。

方法

  • 实例方法第一个参数是 self;调用 s.introduce()。
  • 属性加下划线 _score 表示“内部使用”,靠约定不靠强制。

代码示例

▶ 定义学生类
PYTHON
class Student:
    school = "一中"

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

    def introduce(self):
        return f"我是{self.name},来自{self.school},成绩{self.score}"

s = Student("张三", 89)
print(s.introduce())
👀 运行结果
我是张三,来自一中,成绩89
▶ 类属性共享
PYTHON
a = Student("李四", 92)
Student.school = "二中"
print(a.school)
👀 运行结果
二中

常见错误

⚠️ 踩坑与解决
  • TypeError: __init__() missing 1 required positional argument: 'score'
    → 实例化少传参数;按 __init__ 参数补齐
  • AttributeError: 'Student' object has no attribute 'age'
    → 属性没在 __init__ 里定义;在 __init__ 里赋初值

💡 先在纸上写“名词(属性)+ 动词(方法)”,再翻译成类,比直接写代码快。

6.2

继承与多态

继承复用父类代码,多态让同一句调用产生不同行为。

能用继承复用父类能用 super() 调父类方法能重写方法实现多态

知识点

继承

  • class Dog(Animal): 子类自动拥有父类的方法与属性。
  • super().__init__(name) 先初始化父类那部分。
  • Python 支持多继承,但日常用单继承就够了。

重写与多态

  • 子类定义同名方法即重写;调用时按对象真实类型执行。
  • 多态的价值:父类引用统一调度,新增子类不用改调用代码。

抽象约定

  • 父类方法里 raise NotImplementedError 表示“子类必须实现”。
  • 也可以用 abc.ABC + @abstractmethod 强制实现。

代码示例

▶ 继承与重写
PYTHON
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return "……"

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

print(Dog("旺财").speak())
👀 运行结果
旺财: 汪汪
▶ 多态
PYTHON
class Cat(Animal):
    def speak(self):
        return f"{self.name}: 喵喵"

for pet in [Dog("旺财"), Cat("咪咪")]:
    print(pet.speak())
👀 运行结果
旺财: 汪汪
咪咪: 喵喵

常见错误

⚠️ 踩坑与解决
  • TypeError: super() takes no arguments
    → super 用法写错;python3 写 super().__init__(...)
  • 子类没调用父类 __init__ 导致缺属性
    → 只写了子类初始化;在子类 __init__ 首行加 super().__init__(...)

💡 继承表达“是一种(is-a)”;只是组合不同部件请用属性持有,别硬套继承。

6.3

魔术方法与 dataclass

让对象“看起来像内置类型”:打印好看、能比较、能迭代;dataclass 帮你少写样板代码。

能实现 __str__ / __repr__能实现 __eq__ / __len__能用 @dataclass 简化数据类

知识点

常用魔术方法

  • __str__ 给 print 用,__repr__ 给调试用(尽量可复原)。
  • __eq__ 定义“相等”的含义;__len__ 让 len(obj) 可用。
  • __iter__ 让对象可被 for 遍历。

dataclass

  • @dataclass 自动生成 __init__、__repr__、__eq__。
  • 字段用类型注解声明;要默认值就写 = 0。
  • frozen=True 变成不可变对象,接近元组但带字段名。

什么时候用

  • 主要用来装数据 → dataclass。
  • 有行为、有状态变化 → 普通类。

代码示例

▶ __str__ 与 __eq__
PYTHON
class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y
    def __str__(self):
        return f"({self.x}, {self.y})"
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

print(Point(1, 2))
print(Point(1, 2) == Point(1, 2))
👀 运行结果
(1, 2)
True
▶ dataclass
PYTHON
from dataclasses import dataclass

@dataclass
class Student:
    name: str
    score: float = 0

s = Student("张三", 89)
print(s)
👀 运行结果
Student(name='张三', score=89)

常见错误

⚠️ 踩坑与解决
  • __str__ 返回了非字符串
    → return 了数字或 None;用 f-string 转成字符串
  • dataclass 字段顺序错(有默认值在前)
    → 非默认值字段放在了默认值后面;把无默认值的字段放前面

💡 数据类优先用 dataclass,代码量能少一半,可读性还更好。