📄 本篇摘要
面向对象的地基三词:类(class)=图纸;实例(instance)=按图纸造出的具体产品;对象(object)=实例的别名(口语中常混用)。类把数据(属性)和操作(方法)装进一个盒子——面向对象三大特性(封装、继承、多态)都从这个盒子出发。
一、类是图纸,实例是产品
类 class(图纸) 实例 instance(产品)
┌─────────────────┐ ┌──────────────────┐
│ Dog │ new │ 旺财 (name=旺财) │
│ 属性: name │ ──────> │ 小黑 (name=小黑) │
│ 方法: bark() │ │ ……(各自独立) │
└─────────────────┘ └──────────────────┘
类定义一次,实例可以造无数个——每个实例的属性值各自独立,方法共用同一份定义。这就是面向对象和散装变量的本质区别:数据和行为长在一起,旺财.bark() 而不是 bark(旺财的名字)。
二、三大特性总览(本章后半章逐一展开)
- 封装(5-18):把细节藏起来,只公开接口——遥控器不必懂电视内部电路;
- 继承(5-16):子类自动获得父类的属性与方法——【哺乳动物】的知识【狗】直接继承;
- 多态(5-19):同一方法名,不同类各自实现——同样的
speak(),猫喵狗汪。
教材提示:三大特性不是教条,是管理复杂度的工具——程序小时随便写,程序大了靠它们分而治之。
三、动手 Demo:第一张图纸
class Dog:
"""图纸:狗 = 名字 + 叫"""
species = "犬科" # 类变量:所有实例共享
def __init__(self, name, age): # 造实例时的初始化(5-25 展开)
self.name = name # 实例变量:每只狗独立
self.age = age
def bark(self): # 方法
return f"{self.name}({self.age}岁): 汪!"
def birthday(self): # 方法操作自己的数据
self.age += 1
return self.age
# 图纸 -> 产品
wangcai = Dog("旺财", 3)
xiaohei = Dog("小黑", 1)
print(wangcai.bark())
print(xiaohei.bark())
print(Dog.species, "==", wangcai.species) # 类变量大家共享
print(wangcai.birthday(), wangcai.birthday()) # 只动了旺财的年龄
# 验证【属性独立】:旺财过生日,小黑没变
print(xiaohei.age)
沙箱实跑输出:
旺财(3岁): 汪!
小黑(1岁): 汪!
犬科 == 犬科
4 5
1
看到什么算成功:两只狗叫声里名字年龄各归各;旺财连过两个生日到 5 岁,小黑还是 1。
读结果:species 是类变量(所有狗共享一份),name/age 是实例变量(每只狗一份)——共享与独立的分界是面向对象的第一课。birthday 方法改的是自己的数据:数据与操作长在一起的活例证。
四、30 秒实验
把 species 改赋值到实例上(wangcai.species = "特俗品种")再打印 xiaohei.species——小黑仍是犬科。实例赋值只造了旺财自己的副本,类变量本体没动(遮蔽现象,和 4-6 作用域同款逻辑)。
五、常见误区
| 误区 | 真相 |
|---|---|
| 类和对象是一个东西 | 类是图纸(存在于代码里),对象是运行时造出的产品 |
| 方法一定要传一堆参数 | 方法自带 self——数据和行为长在一起,不必东拼西凑 |
| 实例变量和类变量随便混用 | 共享的(常量、计数器)用类变量,独立的用实例变量;混用出诡异 bug |
自测三问(点击展开)
1. **类、实例、对象三词的关系?** 答:类是图纸;实例是按图纸造出的产品;对象基本是实例的同义词。 2. **`__init__` 什么时候执行?** 答:每次 new 一个实例时执行,负责初始化该实例自己的属性。 3. **类变量和实例变量的取舍?** 答:所有实例共享的用类变量,各实例独立的用实例变量。- ☐ 5-15 学习完成
相关笔记
- C++ 10.1 · C++类 —— 同一张图纸的 C++ 画法
- C++ 10.2 · 构造函数 —— 初始化在 C++ 里的写法
- 构造与析构 —— 初始化与释放的专题
- ⌨️ 编程原理 · 索引 —— 全课路线图