第6章 面向对象
类与对象、属性与方法、继承与多态、魔术方法与 dataclass。
本章学习目标
- 能定义类、创建对象、访问属性与调用方法
- 理解 __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 表示“内部使用”,靠约定不靠强制。
代码示例
▶ 定义学生类
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
▶ 类属性共享
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 强制实现。
代码示例
▶ 继承与重写
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())👀 运行结果
旺财: 汪汪
▶ 多态
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__
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
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,代码量能少一半,可读性还更好。